引言
设计模式是软件工程中用于解决常见问题的可复用解决方案。在C#编程中,常见的设计模式具有广泛的应用。本篇博客将重点介绍C#中常见的结构型设计模式,包括适配器模式、装饰器模式、代理模式、组合模式和享元模式。
目录
-
- 引言
- [1. 适配器模式(Adapter Pattern)](#1. 适配器模式(Adapter Pattern))
- [2. 桥接模式(Bridge Pattern)](#2. 桥接模式(Bridge Pattern))
- [3. 外观模式(Facade)](#3. 外观模式(Facade))
- [4. 装饰器模式(Decorator Pattern)](#4. 装饰器模式(Decorator Pattern))
- [5. 代理模式(Proxy Pattern)](#5. 代理模式(Proxy Pattern))
- [6. 组合模式(Composite Pattern)](#6. 组合模式(Composite Pattern))
- [7. 享元模式(Flyweight Pattern)](#7. 享元模式(Flyweight Pattern))
- 结论
1. 适配器模式(Adapter Pattern)
适配器模式用于将一个类的接口转换成客户端所期望的另一个接口。这种模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
示例代码
csharp
// 目标接口
interface ITarget
{
void Request();
}
// 需要被适配的类
class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Adaptee's SpecificRequest");
}
}
// 适配器类
class Adapter : ITarget
{
private Adaptee _adaptee;
public Adapter(Adaptee adaptee)
{
_adaptee = adaptee;
}
public void Request()
{
_adaptee.SpecificRequest();
}
}
// 客户端代码
class Client
{
static void Main(string[] args)
{
Adaptee adaptee = new Adaptee();
ITarget target = new Adapter(adaptee);
target.Request();
}
}
解释
适配器模式中的目标接口(ITarget
)定义了客户端所期望的方法。Adaptee
类是需要被适配的类,其中包含了一个SpecificRequest
方法。Adapter
类则是适配器,持有一个Adaptee
对象的引用,并实现了ITarget
接口。在Adapter
的Request
方法中,调用了Adaptee
的SpecificRequest
方法。在客户端代码中,创建了一个Adaptee
对象和一个Adapter
对象,然后通过Adapter
对象去调用Request
方法。
2. 桥接模式(Bridge Pattern)
桥接模式是一种结构型设计模式,用于将抽象与实现隔离开来,使它们能够独立变化。它通过组合的方式代替继承,从而降低了系统的耦合性。该模式适合在需要多个维度进行扩展时使用,例如在图形界面库中,将窗口与不同操作系统的窗口装饰风格进行分离。桥接模式的核心思想是将抽象部分与实现部分分离,使它们可以独立地变化和演化。
示例代码
csharp
// 实现部分接口
interface Implementor {
void operationImpl();
}
// 具体实现类A
class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorA operation implementation");
}
}
// 具体实现类B
class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorB operation implementation");
}
}
// 抽象部分
abstract class Abstraction {
protected Implementor implementor;
public void setImplementor(Implementor implementor) {
this.implementor = implementor;
}
public abstract void operation();
}
// 扩展抽象部分的具体类
class RefinedAbstraction extends Abstraction {
@Override
public void operation() {
implementor.operationImpl();
}
}
// 使用示例
public class BridgePatternExample {
public static void main(String[] args) {
Implementor implementorA = new ConcreteImplementorA();
Implementor implementorB = new ConcreteImplementorB();
Abstraction abstraction = new RefinedAbstraction();
abstraction.setImplementor(implementorA);
abstraction.operation();
abstraction.setImplementor(implementorB);
abstraction.operation();
}
}
解释
在上述示例中,Implementor 接口定义了实现部分的操作方法。ConcreteImplementorA 和ConcreteImplementorB 是具体的实现类。Abstraction 是抽象部分的定义,其中包含一个实现部分的通用接口,并有一个抽象方法 operation() 来定义具体的操作。RefinedAbstraction 是具体的扩展抽象类,实现了抽象方法并通过组合关联了具体的实现类。
3. 外观模式(Facade)
外观模式是一种结构型设计模式,提供了一个统一的接口,用来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。。
示例代码
csharp
// 子系统A
class SubsystemA {
public void operationA() {
System.out.println("SubsystemA operation");
}
}
// 子系统B
class SubsystemB {
public void operationB() {
System.out.println("SubsystemB operation");
}
}
// 子系统C
class SubsystemC {
public void operationC() {
System.out.println("SubsystemC operation");
}
}
// 外观类
class Facade {
private SubsystemA subsystemA;
private SubsystemB subsystemB;
private SubsystemC subsystemC;
public Facade() {
subsystemA = new SubsystemA();
subsystemB = new SubsystemB();
subsystemC = new SubsystemC();
}
public void operation() {
subsystemA.operationA();
subsystemB.operationB();
subsystemC.operationC();
}
}
// 使用示例
public class FacadePatternExample {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
解释
在上述示例中,SubsystemA、SubsystemB 和 SubsystemC 是不同的子系统,它们分别提供了不同的操作。Facade 是外观类,隐藏了子系统的复杂性,为客户端提供了一个简单的接口。在外观类的操作方法中,调用了多个子系统的操作。
4. 装饰器模式(Decorator Pattern)
装饰器模式允许向一个现有对象添加新功能,同时又不改变其结构。它是通过创建一个包装对象来包裹真实对象,从而对真实对象进行功能的扩展。
示例代码
csharp
// 抽象组件接口
interface IComponent
{
void Operation();
}
// 具体组件类
class ConcreteComponent : IComponent
{
public void Operation()
{
Console.WriteLine("ConcreteComponent's Operation");
}
}
// 抽象装饰者类
abstract class Decorator : IComponent
{
protected IComponent _component;
public Decorator(IComponent component)
{
_component = component;
}
public virtual void Operation()
{
_component.Operation();
}
}
// 具体装饰者类
class ConcreteDecoratorA : Decorator
{
public ConcreteDecoratorA(IComponent component)
: base(component)
{
}
public override void Operation()
{
base.Operation();
AddedBehavior();
}
private void AddedBehavior()
{
Console.WriteLine("ConcreteDecoratorA's AddedBehavior");
}
}
class ConcreteDecoratorB : Decorator
{
public ConcreteDecoratorB(IComponent component)
: base(component)
{
}
public override void Operation()
{
base.Operation();
AddedBehavior();
}
private void AddedBehavior()
{
Console.WriteLine("ConcreteDecoratorB's AddedBehavior");
}
}
// 客户端代码
class Client
{
static void Main(string[] args)
{
IComponent component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component = new ConcreteDecoratorB(component);
component.Operation();
}
}
解释
装饰器模式中的抽象组件接口(IComponent
)定义了被装饰者和装饰者之间的公共方法。ConcreteComponent
类是具体的组件类,实现了IComponent
接口的Operation
方法。Decorator
类是抽象装饰者类,持有一个IComponent
对象的引用,并实现了IComponent
接口。ConcreteDecoratorA
和ConcreteDecoratorB
类分别是具体装饰者类,它们继承自Decorator
类,并在调用父类Operation
方法的同时添加了额外的行为。
在客户端代码中,首先创建了一个ConcreteComponent
对象,然后通过多次进行装饰,分别使用ConcreteDecoratorA
和ConcreteDecoratorB
对其进行包装。最后调用component.Operation()
方法时,实际上会调用被装饰者的Operation
方法,并在其基础上添加了额外的行为。
5. 代理模式(Proxy Pattern)
代理模式为其他对象提供一种代理以控制对这个对象的访问。代理模式主要通过代理类来封装目标对象,控制客户端对目标对象的访问,并在必要的时候进行一些预处理或后处理操作。
示例代码
csharp
// 被代理接口
interface ISubject
{
void Request();
}
// 真实对象类
class RealSubject : ISubject
{
public void Request()
{
Console.WriteLine("RealSubject's Request");
}
}
// 代理类
class Proxy : ISubject
{
private RealSubject _realSubject;
public void Request()
{
if (_realSubject == null)
{
_realSubject = new RealSubject();
}
PreProcess();
_realSubject.Request();
PostProcess();
}
private void PreProcess()
{
Console.WriteLine("Proxy's PreProcess");
}
private void PostProcess()
{
Console.WriteLine("Proxy's PostProcess");
}
}
// 客户端代码
class Client
{
static void Main(string[] args)
{
ISubject proxy = new Proxy();
proxy.Request();
}
}
解释
代理模式中的被代理接口(ISubject
)定义了代理对象和真实对象的公共方法。RealSubject
类是真实对象类,实现了被代理接口的Request
方法。Proxy
类是代理类,持有一个RealSubject
对象的引用,并实现了被代理接口的Request
方法。在Proxy
类的Request
方法中,进行了预处理、调用真实对象的Request
方法和后处理。
在客户端代码中,创建了一个代理对象Proxy
,然后通过该对象调用Request
方法。在调用过程中,会对真实对象进行实例化,并在方法执行前后进行相应的预处理和后处理。
6. 组合模式(Composite Pattern)
组合模式将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。
示例代码
csharp
// 抽象组件类
abstract class Component
{
protected string _name;
public Component(string name)
{
_name = name;
}
public abstract void Display();
}
// 叶子节点类
class Leaf : Component
{
public Leaf(string name)
: base(name)
{
}
public override void Display()
{
Console.WriteLine(_name);
}
}
// 容器节点类
class Composite : Component
{
private List<Component> _children = new List<Component>();
public Composite(string name)
: base(name)
{
}
public void Add(Component component)
{
_children.Add(component);
}
public void Remove(Component component)
{
_children.Remove(component);
}
public override void Display()
{
Console.WriteLine(_name);
foreach (Component component in _children)
{
component.Display();
}
}
}
// 客户端代码
class Client
{
static void Main(string[] args)
{
Composite root = new Composite("root");
Leaf leaf1 = new Leaf("leaf1");
Leaf leaf2 = new Leaf("leaf2");
Composite composite1 = new Composite("composite1");
Composite composite2 = new Composite("composite2");
root.Add(leaf1);
root.Add(composite1);
composite1.Add(leaf2);
composite1.Add(composite2);
root.Display();
}
}
解释
组合模式中的抽象组件类(Component
)定义了树状结构中所有对象的通用行为的接口。Leaf
类是叶子节点类,它继承自Component
类,并实现了Display
方法。Composite
类是容器节点类,它继承自Component
类,并持有一组Component
对象。在Composite
类的Display
方法中,首先输出自身信息,然后递归调用所有子节点的Display
方法。
在客户端代码中,首先创建了一个根节点root
和一些叶子节点和容器节点。通过调用容器节点的Add
方法可以将其他节点添加到其内部。最后调用root.Display()
方法,会递归地展示整个树状结构。
7. 享元模式(Flyweight Pattern)
享元模式是一种池技术,主要用于减少创建对象的数量,以减少内存占用和提高性能。享元模式通过共享已创建的对象,避免重复创建相同的对象。
示例代码
csharp
// 享元接口
interface IFlyweight
{
void Operation();
}
// 具体享元类
class ConcreteFlyweight : IFlyweight
{
private readonly string _intrinsicState;
public ConcreteFlyweight(string intrinsicState)
{
_intrinsicState = intrinsicState;
}
public void Operation()
{
Console.WriteLine($"ConcreteFlyweight's Operation with {_intrinsicState}");
}
}
// 享元工厂类
class FlyweightFactory
{
private Dictionary<string, IFlyweight> _flyweights = new Dictionary<string, IFlyweight>();
public IFlyweight GetFlyweight(string key)
{
if (_flyweights.ContainsKey(key))
{
return _flyweights[key];
}
else
{
IFlyweight flyweight = new ConcreteFlyweight(key);
_flyweights.Add(key, flyweight);
return flyweight;
}
}
}
// 客户端代码
class Client
{
static void Main(string[] args)
{
FlyweightFactory factory = new FlyweightFactory();
IFlyweight flyweight1 = factory.GetFlyweight("key1");
flyweight1.Operation();
IFlyweight flyweight2 = factory.GetFlyweight("key2");
flyweight2.Operation();
IFlyweight flyweight3 = factory.GetFlyweight("key1");
flyweight3.Operation();
}
}
解释
享元模式中的享元接口(IFlyweight
)定义了享元类的公共方法。ConcreteFlyweight
类是具体享元类,它实现了IFlyweight
接口,并持有一个内部状态(_intrinsicState
)。FlyweightFactory
类是享元工厂类,用于创建和管理享元对象。
在客户端代码中,首先创建了一个FlyweightFactory
对象。通过调用工厂的GetFlyweight
方法可以获取享元对象,如果对象已经存在,则直接返回已有对象;如果对象不存在,则创建新的享元对象并将其缓存起来。最后调用享元对象的Operation
方法时,会输出其内部状态。
结论
结构型设计模式在C#编程中具有广泛的应用。适配器模式用于解决不兼容接口的问题,装饰器模式用于动态地扩展对象的功能,代理模式用于控制对对象的访问,组合模式用于处理树状结构数据,享元模式用于减少对象创建的数量。合理使用这些结构型设计模式可以提高代码的可读性、可维护性和可扩展性。
参考资料: