ToB企服应用市场:ToB评测及商务社交产业平台

标题: 23种设计模式 [打印本页]

作者: 篮之新喜    时间: 2024-1-3 16:38
标题: 23种设计模式
  设计模式(design pattern)是软件工程中的一种重要技术,它是在特定的上下文环境中,为解决特定问题而采用的一种通用的解决方案。设计模式可以帮助软件工程师提高代码的可复用性、可维护性和可扩展性。
  23 种常见设计模式可以分为以下几类:
1、工厂模式(Factory Pattern): 创建一个工厂类,用于创建其他类的实例。
  工厂模式是一种创建型设计模式,它提供了一种创建对象的方式,而不需要直接实例化类。工厂模式将创建对象的过程封装在一个单独的工厂类中,客户端可以通过工厂类来创建所需的对象,而无需关心对象的具体实现细节。
  工厂模式可以分为简单工厂模式、工厂方法模式和抽象工厂模式。
  简单工厂模式:提供一个工厂类,它可以根据传入的参数创建不同的产品对象。
  工厂方法模式:定义一个工厂接口,让不同的子类实现这个接口,客户端可以通过调用工厂接口来创建不同的产品对象。   抽象工厂模式:提供一个抽象工厂接口,让不同的子类实现这个接口,客户端可以通过调用抽象工厂接口来创建一系列相关的产品对象。  工厂模式的优点和缺点如下: 优点: 缺点: 在实际应用中,工厂模式通常用于创建复杂对象、提高代码的可复用性和可扩展性。选择使用哪种工厂模式取决于具体的需求和场景。     以下是一些常见的应用场景: 总之,工厂模式可以在许多场景中使用,它通过提供一个工厂类来创建一系列相关或相互依赖的对象,从而提高代码的灵活性、可复用性和可维护性。在实际应用中,需要根据具体的业务场景来选择合适的工厂模式实现方式。       下面是一个简单的 C#工厂类示例,演示如何使用工厂模式创建不同类型的产品对象:   查看代码
  1. using System;
  2. public interface IProduct
  3. {
  4.     void DoSomething();
  5. }
  6. public class ConcreteProductA : IProduct
  7. {
  8.     public void DoSomething()
  9.     {
  10.         Console.WriteLine("Product A doing something...");
  11.     }
  12. }
  13. public class ConcreteProductB : IProduct
  14. {
  15.     public void DoSomething()
  16.     {
  17.         Console.WriteLine("Product B doing something...");
  18.     }
  19. }
  20. public class Factory
  21. {
  22.     public IProduct CreateProduct(string productName)
  23.     {
  24.         if (productName.Equals("Product A"))
  25.         {
  26.             return new ConcreteProductA();
  27.         }
  28.         else if (productName.Equals("Product B"))
  29.         {
  30.             return new ConcreteProductB();
  31.         }
  32.         else
  33.         {
  34.             throw new ArgumentException("Invalid product name.");
  35.         }
  36.     }
  37. }
复制代码
  在上述示例中,我们定义了一个IProduct接口和两个具体的产品类ConcreteProductA和ConcreteProductB。然后,我们定义了一个工厂类Factory,它包含一个CreateProduct方法,根据传入的产品名称创建相应的产品对象。
  要使用工厂类创建产品对象,可以这样做:
查看代码
  1.  Factory factory = new Factory();
  2. IProduct productA = factory.CreateProduct("Product A");
  3. IProduct productB = factory.CreateProduct("Product B");
  4. productA.DoSomething(); // Output: Product A doing something...
  5. productB.DoSomething(); // Output: Product B doing something...
复制代码
 在上述示例中,我们创建了一个工厂对象,并使用它创建了两个产品对象productA和productB。然后,我们分别调用这两个产品对象的DoSomething方法,输出相应的信息。
  2、抽象工厂模式(Abstract Factory Pattern): 创建一个抽象工厂类,用于创建一组相关类的实例。
  抽象工厂模式是一种创建型设计模式,用于提供一个接口,用于创建一系列相关或依赖对象,而无需指定它们的具体类。   抽象工厂模式的主要优点是提高了代码的可扩展性和灵活性。通过抽象工厂类,可以将创建对象的具体细节隐藏起来,使得客户端代码可以通过抽象工厂类来创建所需的对象,而无需关心具体的实现细节。 抽象工厂模式的主要角色包括:
抽象工厂模式的优点和缺点如下: 优点: 缺点: 综上所述,抽象工厂模式在实际项目中可以提供封装和抽象、提高灵活性和减少代码重复,但也可能增加复杂度和导致单点故障。因此,在使用抽象工厂模式时,需要根据具体情况进行权衡和选择。  以下是一些常见的应用场景: 总之,抽象工厂模式可以在许多场景中使用,它通过提供一个抽象工厂接口来创建一系列相关或相互依赖的对象,从而提高代码的灵活性、可复用性和可维护性。在实际应用中,需要根据具体的业务场景来选择合适的抽象工厂模式实现方式。  下面是一个简单的抽象工厂模式示例
查看代码
  1. using System;
  2. public interface IFactory
  3. {
  4.     IProductA CreateProductA();
  5.     IProductB CreateProductB();
  6. }
  7. public interface IProductA
  8. {
  9.     void DoSomething();
  10. }
  11. public interface IProductB
  12. {
  13.     void DoSomething();
  14. }
  15. public class ConcreteFactoryA : IFactory
  16. {
  17.     public IProductA CreateProductA()
  18.     {
  19.         return new ConcreteProductA();
  20.     }
  21.     public IProductB CreateProductB()
  22.     {
  23.         return new ConcreteProductB();
  24.     }
  25. }
  26. public class ConcreteFactoryB : IFactory
  27. {
  28.     public IProductA CreateProductA()
  29.     {
  30.         return new ConcreteProductA();
  31.     }
  32.     public IProductB CreateProductB()
  33.     {
  34.         return new ConcreteProductB();
  35.     }
  36. }
  37. public class ConcreteProductA : IProductA
  38. {
  39.     public void DoSomething()
  40.     {
  41.         Console.WriteLine("Product A doing something...");
  42.     }
  43. }
  44. public class ConcreteProductB : IProductB
  45. {
  46.     public void DoSomething()
  47.     {
  48.         Console.WriteLine("Product B doing something...");
  49.     }
  50. }
  51. public class Client
  52. {
  53.     public void UseFactory()
  54.     {
  55.         IFactory factoryA = new ConcreteFactoryA();
  56.         IFactory factoryB = new ConcreteFactoryB();
  57.         IProductA productA = factoryA.CreateProductA();
  58.         IProductB productB = factoryA.CreateProductB();
  59.         productA.DoSomething();
  60.         productB.DoSomething();
  61.         IProductA productA2 = factoryB.CreateProductA();
  62.         IProductB productB2 = factoryB.CreateProductB();
  63.         productA2.DoSomething();
  64.         productB2.DoSomething();
  65.     }
  66. }
复制代码
在上述示例中,我们定义了一个抽象工厂接口IFactory,以及两个具体工厂类ConcreteFactoryA和ConcreteFactoryB。然后,我们定义了两个抽象产品接口IProductA和IProductB,以及两个具体产品类ConcreteProductA和ConcreteProductB。 在Client类中,我们创建了两个具体工厂对象factoryA和factoryB,并使用它们创建了具体的产品对象productA、productB、productA2和productB2。然后,我们分别调用这些产品对象的DoSomething方法。    使用抽象工厂模式时,需要注意以下几个问题: 总之,抽象工厂模式是一种常用的设计模式,它可以提高代码的可扩展性和灵活性,但同时也需要注意其缺点和限制,根据具体的需求和场景来选择是否使用该模式。    3、单例模式(Singleton Pattern): 确保一个类只有一个实例,并提供全局访问该实例的方法。
  单例模式分为饿汉式单例模式和懒汉式单例模式两种不同的实现方式,它们的区别主要在于单例模式对象的创建时机。
  饿汉式单例模式(Eager Initialization Singleton Pattern)在类加载时就创建单例对象,并提供全局访问该对象的方式。这种方式的优点是在程序启动时就创建了单例对象,因此可以立即使用,不需要等待创建过程,从而提高了程序的性能。
  懒汉式单例模式(LazyInitialization Singleton Pattern)在第一次请求实例时才创建单例对象。这种方式的优点是可以避免在程序启动时就创建单例对象,从而减少了资源的浪费和初始化时间。
下面是一个使用C#实现的饿汉式单例模式的示例: 
查看代码
  1. using System;
  2. class Singleton
  3. {
  4.     private static Singleton instance = new Singleton();
  5.     private Singleton()
  6.     {
  7.     }
  8.     public static Singleton GetInstance()
  9.     {
  10.         return instance;
  11.     }
  12. }
复制代码
  在上面的示例中,instance 是一个私有静态变量,用于保存单例对象。在类加载时,就会创建一个新的单例对象并返回。因此,每次调用 getInstance() 方法都会返回同一个单例对象。
下面是一个使用 C# 实现的懒汉式单例模式的示例:
查看代码
  1.  using System;
  2. class LazySingleton
  3. {
  4.     private static LazySingleton instance = null;
  5.     private LazySingleton()
  6.     {
  7.     }
  8.     public static LazySingleton GetInstance()
  9.     {
  10.         if (instance == null)
  11.         {
  12.             instance = new LazySingleton();
  13.         }
  14.         return instance;
  15.     }
  16. }
复制代码
  在上面的示例中,instance 是一个私有静态变量,用于保存单例对象。在 getInstance() 方法中,如果 instance 为 null,则创建一个新的单例对象并返回。否则,直接返回 instance 变量中的单例对象。
  总的来说,饿汉式单例模式的优点是可以立即使用单例对象,而懒汉式单例模式的优点是可以避免在程序启动时就创建单例对象,从而减少了资源的浪费和初始化时间。但是,如果单例对象的创建过程比较耗时或者需要访问共享资源,那么可能会导致线程安全问题。为了解决这个问题,可以使用线程安全的方式来创建单例对象,例如使用同步块或者使用双重检查锁定机制。
单例模式的优点和缺点如下: 优点: 缺点: 综上所述,单例模式在实际项目中可以提供全局唯一对象、方便管理和控制、提高性能和简化代码结构,但也可能导致单点故障、不利于扩展和测试以及线程安全问题。因此,在使用单例模式时,需要根据具体情况进行权衡和选择。 以下是一些常见的应用场景:
  ① 共享资源:在程序中,有些资源需要在整个程序中共享,例如数据库连接、文件句柄、网络连接等。使用单例模式可以确保只有一个实例来管理这些共享资源,从而避免了资源的重复创建和释放。
  ② 工具类:工具类通常不需要创建多个实例,因为它们提供的功能是全局可用的。通过将工具类设计为单例模式,可以避免多吃创建实例,提高代码的效率和性能。
  ③ 配置类:程序中的配置信息通常只需要一个实例来管理。使用单例模式可以确保只有一个配置类实例,并提供全局访问配置信息的方式。
  ④ 日志类:日志类通常用于记录程序的运行信息,并且只需要一个实例来管理日志输出。通过将日志类设计为单例模式,可以方便地在程序中全局访问日志记录功能。
       ⑤ 线程池:线程池是一种用于管理线程的资源池,它只需要创建一个实例来管理线程的分配和回收。通过将线程池设计为单例模式,可以避免多次创建线程池实例,提高程序的性能和效率。
  ⑥ 计数器:计数器用于记录某些时间的发生次数,例如页面访问次数、用户登录次数等。通过将计数器设计为单例模式。可以方便地在程序中全局访问计数器,并确保技术器的唯一性和准确性。
  总之,单例模式适用于那些只需要一个实例来管理共享资源、提供全局访问功能的类。通过使用单例模式,可以避免资源的重复创建和释放,提高代码的效率和性能,同时也可以方便地在程序中全局访问单例对象。
   4、建造者模式(Builder Pattern):将一个复杂对象的创建过程分解为多个步骤,并通过一个建造者类来管理这些步骤。
在建造者模式中,通常有以下几个角色: 建造者模式的工作流程如下:   通过使用建造者模式,我们可以将复杂对象的创建过程分解为多个步骤,并通过具体建造者类来实现这些步骤的定制和扩展。同时,指挥者类可以协调不同的建造者对象来创建不同类型的产品对象,从而提高了代码的灵活性和可扩展性。建造者模式还可以隐藏具体产品类的实现细节,使代码更加模块化和易于维护。  建造者模式的优点和缺点如下: 优点: 缺点:
  综上所述,建造者模式在实际项目中可以提供封装复杂对象的创建过程、提高代码可读性和可维护性、支持灵活的对象创建以及减少代码重复等优点,但也可能导致类的数量增加、构造过程复杂以及难以扩展等缺点。在使用建造者模式时,需要根据具体情况进行权衡和选择。  以下是一些常见的应用场景: 总之,建造者模式可以在许多场景中使用,它通过将复杂对象的创建过程分解为多个步骤,并通过一个指挥者对象来协调这些步骤的执行,从而简化对象的创建过程,提高代码的灵活性、可读性和可维护性。在实际应用中,需要根据具体的业务场景来选择合适的建造者模式实现方式。     以下是使用 C# 实现建造者模式的示例代码: 查看代码
  1.  using System;
  2. public abstract class Builder
  3. {
  4.     protected abstract void BuildPartA();
  5.     protected abstract void BuildPartB();
  6.     public void Build()
  7.     {
  8.         BuildPartA();
  9.         BuildPartB();
  10.     }
  11.     public abstract Product GetProduct();
  12. }
  13. public class ConcreteBuilderA : Builder
  14. {
  15.     private Product _product = new Product();
  16.     protected override void BuildPartA()
  17.     {
  18.         _product.PartA = "Part A A";
  19.     }
  20.     protected override void BuildPartB()
  21.     {
  22.         _product.PartB = "Part B A";
  23.     }
  24.     public override Product GetProduct()
  25.     {
  26.         return _product;
  27.     }
  28. }
  29. public class ConcreteBuilderB : Builder
  30. {
  31.     private Product _product = new Product();
  32.     protected override void BuildPartA()
  33.     {
  34.         _product.PartA = "Part A B";
  35.     }
  36.     protected override void BuildPartB()
  37.     {
  38.         _product.PartB = "Part B B";
  39.     }
  40.     public override Product GetProduct()
  41.     {
  42.         return _product;
  43.     }
  44. }
  45. public class Product
  46. {
  47.     public string PartA { get; set; }
  48.     public string PartB { get; set; }
  49. }
  50. public class Director
  51. {
  52.     public void Construct(Builder builder)
  53.     {
  54.         builder.Build();
  55.     }
  56.     public Product GetProduct(Builder builder)
  57.     {
  58.         return builder.GetProduct();
  59.     }
  60. }
复制代码
  在这个示例中,Builder 类是抽象的建造者类,它定义了建造产品的接口,包括 BuildPartA 和 BuildPartB 方法,用于设置产品的属性。ConcreteBuilderA 和 ConcreteBuilderB 是具体的建造者类,它们实现了 Builder 接口,并提供了具体的产品创建逻辑。Product 类是产品类,它定义了产品的抽象接口,包括 PartA 和 PartB 属性。Director 类是指挥者类,它负责协调建造者对象来创建产品对象。在 Construct 方法中,指挥者对象调用建造者对象的 BuildPartA 和 BuildPartB 方法来设置产品属性。在 GetProduct 方法中,指挥者对象调用建造者对象的 GetProduct 方法来获取创建好的产品对象。  5、原型模式(Prototype Pattern):通过复制一个已有的对象来创建新的对象。
在原型模式中,我们定义一个原型类(Prototype),它提供了一个克隆方法(Clone),可以通过该方法创建一个与自身完全相同的新对象。 原型模式的优点和缺点如下: 优点: 缺点:   以下是一些常见的应用场景: 总之,原型模式可以在许多场景中使用,它通过创建一个原型对象来复制和创建其他对象,从而提高创建对象的效率、灵活性和可扩展性。在实际应用中,需要根据具体的业务场景来选择合适的原型模式实现方式。  下面是使用 C# 实现原型模式的示例代码:
查看代码
  1.  using System;
  2. public class Shape
  3. {
  4.     public string Name { get; set; }
  5. }
  6. public class Circle : Shape
  7. {
  8.     public override string Name
  9.     {
  10.         get { return "Circle"; }
  11.     }
  12. }
  13. public class Square : Shape
  14. {
  15.     public override string Name
  16.     {
  17.         get { return "Square"; }
  18.     }
  19. }
  20. public class PrototypePattern
  21. {
  22.     private Shape _shape;
  23.     public PrototypePattern()
  24.     {
  25.         _shape = new Circle();
  26.     }
  27.     public void SetShape(Shape shape)
  28.     {
  29.         _shape = shape;
  30.     }
  31.     public Shape GetShape()
  32.     {
  33.         return _shape.Clone();
  34.     }
  35.     public void DrawShape()
  36.     {
  37.         Console.WriteLine("Drawing shape: " + _shape.Name);
  38.     }
  39. }
  40. public class Program
  41. {
  42.     public static void Main()
  43.     {
  44.         PrototypePattern pattern = new PrototypePattern();
  45.         pattern.DrawShape();
  46.         Shape circle = new Circle();
  47.         pattern.SetShape(circle);
  48.         pattern.DrawShape();
  49.         Shape square = new Square();
  50.         pattern.SetShape(square);
  51.         pattern.DrawShape();
  52.     }
  53. }
复制代码
在这个示例中,我们定义了一个 Shape 抽象类和两个具体的子类 Circle 和 Square。然后,我们定义了一个 PrototypePattern 类,它包含一个 Shape 类型的私有成员变量 _shape,用于存储当前的形状实例。 在 PrototypePattern 类中,我们提供了三个方法:
在 Program 类中,我们创建了一个 PrototypePattern 对象,并调用了 DrawShape 方法来输出默认的圆形形状。然后,我们创建了一个圆形形状对象和一个方形形状对象,并将它们分别传递给 SetShape 方法来更新当前的形状实例。最后,我们再次调用 DrawShape 方法来输出更新后的形状名称。 通过使用原型模式,我们可以通过复制现有的形状实例来创建新的形状实例,而无需通过继承来扩展形状的种类。这样可以提高代码的灵活性和可扩展性,同时也可以避免由于继承带来的复杂性和耦合性。 6、适配器模式(Adapter Pattern):将一个类的接口转换为另外一个类的接口,以便能够使用不同的类。
  适配器模式属于结构型模式。它将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 适配器模式又分为类适配器模式和对象适配器模式:
使用适配器模式可以解决以下问题: 总的来说,适配器模式可以帮助我们解决类之间的接口不匹配问题,使得不同的类能够协同工作,提高代码的复用性和可维护性。
适配器模式的优点和缺点如下: 优点: 缺点: 综上所述,适配器模式在实际项目中可以提供提高代码的可复用性、增强代码的可扩展性、减少代码的重复以及提高代码的可读性和可维护性等优点,但也可能导致类的数量增加、过度适配、影响性能以及难以测试等缺点。在使用适配器模式时,需要根据具体情况进行权衡和选择。    以下是一些常见的应用场景: 总之,适配器模式可以在许多场景中使用,它通过将一个类的接口转换成另一个接口,使不同的类能够一起工作。在实际应用中,需要根据具体的业务场景来选择合适的适配器模式实现方式。    下面是一个使用 C# 实现类适配器模式的示例代码: 查看代码
  1.  using System;
  2. interface ITarget
  3. {
  4.     void MethodA();
  5. }
  6. class Adaptee
  7. {
  8.     public void MethodB()
  9.     {
  10.         Console.WriteLine("这是适配者的方法 B");
  11.     }
  12. }
  13. class Adapter : Adaptee, ITarget
  14. {
  15.     public void MethodA()
  16.     {
  17.         Console.WriteLine("这是适配器的方法 A");
  18.     }
  19. }
复制代码
在上述示例中,我们定义了一个ITarget接口和一个Adaptee类。ITarget接口定义了一个方法MethodA,而Adaptee类中定义了一个方法MethodB。 然后,我们创建了一个Adapter类,它继承自Adaptee类并实现了ITarget接口。在Adapter类中,我们重写了MethodA方法,使其输出"这是适配器的方法 A"。 这样,我们就可以将Adapter类作为ITarget接口的实现类来使用,同时也可以调用Adaptee类中的方法MethodB。这就是类适配器模式的实现方式。 下面是一个使用类适配器模式的示例代码: 查看代码
  1.  class Program
  2. {
  3.     static void Main()
  4.     {
  5.         ITarget target = new Adapter();
  6.         target.MethodA();  // 输出:这是适配器的方法 A
  7.         ((Adapter)target).MethodB();  // 输出:这是适配者的方法 B
  8.     }
  9. }
复制代码
在上述示例中,我们创建了一个ITarget接口的实例target,并将其赋值为一个Adapter类的实例。然后,我们调用了target的MethodA方法和Adapter类的MethodB方法,输出了相应的结果。
  7、桥接模式(Bridge Pattern):将一个抽象类和一个实现类分离,以便在不同的上下文中使用。
  桥接模式是一种结构型设计模式,用于将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过引入一个抽象接口和一个实现接口来实现这种分离。
  桥接模式的结构如下所示:
  Abstraction(抽象类):定义抽象部分的接口。
   RefinedAbstraction(精致抽象类):扩展了抽象类,并实现了具体的操作。
   Implementor(实现类):定义实现部分的接口。
   ConcreteImplementor(具体实现类):实现了实现类的接口,并提供了具体的实现。
桥接模式的优点和缺点如下:
 优点:
  1. 提高了代码的可维护性和可扩展性,因为抽象部分和实现部分可以独立地变化。
   2. 允许在运行时选择不同的实现,从而提高了系统的灵活性。
  3. 分离了抽象部分和实现部分,使得代码更加清晰和易于理解。
 缺点:
  1. 增加了类的数量,可能会导致代码复杂度的增加。
  2. 在某些情况下,可能会导致性能下降,因为需要在运行时进行动态绑定。
以下是一些常见的应用场景: 总之,桥接模式可以在许多场景中使用,它通过将抽象部分与实现部分分离,使它们可以独立地变化。在实际应用中,需要根据具体的业务场景来选择合适的桥接模式实现方式。 以下是一个简单的 C# 示例,演示如何实现桥接模式:
  1. using System;
  2. public interface IDevice
  3. {
  4.     void Initialize();
  5.     void DoSomething();
  6. }
  7. public interface IAdapter
  8. {
  9.     void Initialize();
  10.     void DoSomething();
  11. }
  12. public abstract class Device : IDevice
  13. {
  14.     protected void Initialize()
  15.     {
  16.         Console.WriteLine("Device Initialize");
  17.     }
  18.     protected void DoSomething()
  19.     {
  20.         Console.WriteLine("Device DoSomething");
  21.     }
  22. }
  23. public class Adapter : IAdapter
  24. {
  25.     protected IDevice device;
  26.     public Adapter(IDevice device)
  27.     {
  28.         this.device = device;
  29.     }
  30.     public void Initialize()
  31.     {
  32.         device.Initialize();
  33.     }
  34.     public void DoSomething()
  35.     {
  36.         device.DoSomething();
  37.     }
  38. }
  39. public class ConsoleDevice : Device
  40. {
  41.     public ConsoleDevice()
  42.     {
  43.         Initialize();
  44.     }
  45. }
  46. public class ConsoleAdapter : Adapter, IDevice
  47. {
  48.     public ConsoleAdapter()
  49.     {
  50.         Initialize();
  51.     }
  52. }
  53. public class Program
  54. {
  55.     public static void Main()
  56.     {
  57.         ConsoleDevice consoleDevice = new ConsoleDevice();
  58.         ConsoleAdapter consoleAdapter = new ConsoleAdapter(consoleDevice);
  59.         consoleAdapter.DoSomething();
  60.     }
  61. }
复制代码
  在上述示例中,我们定义了两个接口IDevice和IAdapter,分别代表设备和适配器的抽象行为。然后,我们创建了一个抽象类Device,它实现了IDevice接口,并提供了设备的初始化和操作方法。接下来,我们创建了一个具体的设备类ConsoleDevice,它继承自Device类,并提供了设备的具体实现。然后,我们创建了一个具体的适配器类ConsoleAdapter,它继承自Adapter类和IDevice接口,并实现了设备的初始化和操作方法。在构造函数中,我们将一个具体的设备传递给适配器,以便在运行时进行设备的初始化和操作。最后,我们在Program类中创建了一个具体的设备和适配器,并调用了适配器的操作方法。   通过这种方式,我们实现了桥接模式,将设备的抽象部分和具体实现部分分离,并通过适配器进行连接。这样,我们可以在运行时根据需要选择不同的设备和适配器,从而实现设备的灵活配置和使用。 8、组合模式(Composite Pattern):将一组对象组合成一个树形结构,并提供统一的访问方式。
  组合模式是一种结构型设计模式,它允许将对象组合成树形结构,以表示具有层次结构的整体-部分关系。组合模式使得客户端可以统一地处理单个对象和组合对象,而无需关心对象的层次结构。   组合模式的核心思想是将对象组合成树形结构,并提供一个统一的接口来访问和操作整个树形结构。在组合模式中,有以下三个角色: 组合模式的工作原理如下: 组合模式的优点和缺点如下: 优点:   缺点: 以下是一些常见的应用场景: 总之,组合模式可以在许多场景中使用,它通过将对象组合成树形结构,从而表示具有“整体-部分”关系的层次结构。在实际应用中,需要根据具体的业务场景来选择合适的组合模式实现方式。  以下是一个简单的 C# 示例,演示如何实现组合模式: 查看代码
  1.  using System;
  2. public interface IComponent
  3. {
  4.     void Add(IComponent component);
  5.     void Remove(IComponent component);
  6.     void Operation();
  7. }
  8. public class Leaf : IComponent
  9. {
  10.     public void Add(IComponent component) { }
  11.     public void Remove(IComponent component) { }
  12.     public void Operation() { Console.WriteLine("Leaf Operation"); }
  13. }
  14. public class Composite : IComponent
  15. {
  16.     private readonly IComponent[] components;
  17.     public Composite(IComponent[] components)
  18.     {
  19.         this.components = components;
  20.     }
  21.     public void Add(IComponent component)
  22.     {
  23.         components.Add(component);
  24.     }
  25.     public void Remove(IComponent component)
  26.     {
  27.         components.Remove(component);
  28.     }
  29.     public void Operation()
  30.     {
  31.         foreach (var component in components)
  32.         {
  33.             component.Operation();
  34.         }
  35.     }
  36. }
  37. public class Program
  38. {
  39.     public static void Main()
  40.     {
  41.         var composite = new Composite(new Leaf(), new Composite(new Leaf(), new Leaf()));
  42.         composite.Operation();
  43.     }
  44. }
复制代码
    在上述示例中,我们定义了一个抽象组件IComponent接口,包含了添加、删除和操作子组件的方法。然后,我们创建了一个叶子组件Leaf和一个组合组件Composite,分别实现了IComponent接口。组合组件Composite包含一个子组件数组,并实现了IComponent接口的方法。在操作方法中,组合组件递归地调用子组件的操作方法,以实现整个树形结构的操作。最后,在Program类中,我们创建了一个组合组件,并调用其操作方法来演示组合模式的工作原理。   通过这种方式,我们实现了组合模式,将对象组合成树形结构,并提供了统一的接口来访问和操作整个树形结构。组合模式可以用于处理具有层次结构的复杂对象,如文件系统、组织结构等。  9、装饰器模式(Decorator Pattern):动态地为一个类添加新的功能。
  装饰器模式是一种结构型设计模式,它允许在不改变现有类的基础上,动态地为类添加新的功能。这种模式通过创建一个装饰器类来包装原始类,并在装饰器类中添加新的功能,从而实现对原始类的扩展。 装饰器模式的优点和缺点如下: 优点: 缺点: 以下是一些常见的应用场景: 总之,装饰器模式可以在许多场景中使用,它通过动态地为类或对象添加新的功能,从而提高了代码的灵活性和可扩展性。在实际应用中,需要根据具体的业务场景来选择合适的装饰器模式实现方式。 下面是一个使用 C# 实现装饰器模式的示例:
查看代码
  1.  using System;
  2. public class Component
  3. {
  4.     public void Operation()
  5.     {
  6.         Console.WriteLine("Component's operation");
  7.     }
  8. }
  9. public class Decorator : Component
  10. {
  11.     private Component component;
  12.     public Decorator(Component component)
  13.     {
  14.         this.component = component;
  15.     }
  16.     public override void Operation()
  17.     {
  18.         component.Operation();
  19.         Console.WriteLine("Decorator's operation");
  20.     }
  21. }
  22. public class ConcreteDecoratorA : Decorator
  23. {
  24.     public ConcreteDecoratorA(Component component) : base(component)
  25.     {
  26.     }
  27.     public override void Operation()
  28.     {
  29.         base.Operation();
  30.         Console.WriteLine("ConcreteDecoratorA's operation");
  31.     }
  32. }
  33. public class ConcreteDecoratorB : Decorator
  34. {
  35.     public ConcreteDecoratorB(Component component) : base(component)
  36.     {
  37.     }
  38.     public override void Operation()
  39.     {
  40.         base.Operation();
  41.         Console.WriteLine("ConcreteDecoratorB's operation");
  42.     }
  43. }
  44. public class Client
  45. {
  46.     public static void Main()
  47.     {
  48.         Component component = new Component();
  49.         component.Operation(); // Output: Component's operation
  50.         Decorator decorator = new Decorator(component);
  51.         decorator.Operation(); // Output: Component's operationDecorator's operation
  52.         ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(decorator);
  53.         concreteDecoratorA.Operation(); // Output: Component's operationDecorator's operationConcreteDecoratorA's operation
  54.         ConcreteDecoratorB concreteDecoratorB = new concreteDecoratorB(decorator);
  55.         concreteDecoratorB.Operation(); // Output: Component's operationDecorator's operationConcreteDecoratorA's operationConcreteDecoratorB's operation
  56.     }
  57. }
复制代码
  在上面的示例中,Component 是一个基础类,它定义了一个基本的操作方法。Decorator 是一个装饰器类,它继承自 Component 并添加了一个额外的操作方法。ConcreteDecoratorA 和 ConcreteDecoratorB 是两个具体的装饰器类,它们分别继承自 Decorator 并添加了自己的操作方法。在 Client 类的 Main 方法中,我们创建了一个 Component 对象和三个装饰器对象,并分别调用它们的操作方法。通过这种方式,我们可以在不修改 Component 类的情况下,为其添加不同的装饰器,从而实现了动态地扩展 Component 类的功能。   这只是一个简单的装饰器模式的实现示例,实际应用中可能会更加复杂。装饰器模式可以用于许多场景,例如为类添加额外的功能、修改类的行为等。通过使用装饰器模式,可以提高代码的灵活性和可扩展性,同时也有助于代码的维护和管理。 10、外观模式(Facade Pattern):提供一个简化的接口,隐藏系统的复杂性。
  外观模式是一种结构型设计模式,它为复杂的子系统提供了一个统一的、简化的高层接口,使得子系统更易于使用和管理。主要目的是将子系统的复杂逻辑封装在一个外观类中,为客户端提供一个简单的接口,从而降低子系统与客户端之间的耦合度。外观类通常作为子系统的入口点,它提供了对子系统中各个功能的调用方法,并隐藏了子系统的内部细节。  外观模式的优点和缺点如下: 优点: 缺点: 综上所述,外观模式在实际项目中可以简化接口、提高可维护性和降低耦合度,但也可能增加复杂度和导致单点故障。因此,在使用外观模式时,需要根据具体情况进行权衡和选择。    以下是一些常见的应用场景: 总之,外观模式可以在许多场景中使用,它通过提供一个统一的接口,使得子系统的使用更加简单和方便,同时也提高了系统的可维护性、安全性和可扩展性。在实际应用中,需要根据具体的业务场景来选择合适的外观模式实现方式。   下面是一个使用 C# 实现外观模式的示例: 查看代码
  1.  using System;
  2. public class SubSystemA
  3. {
  4.     public void MethodA()
  5.     {
  6.         Console.WriteLine("SubSystemA's MethodA");
  7.     }
  8. }
  9. public class SubSystemB
  10. {
  11.     public void MethodB()
  12.     {
  13.         Console.WriteLine("SubSystemB's MethodB");
  14.     }
  15. }
  16. public class Facade
  17. {
  18.     private SubSystemA subsystemA;
  19.     private SubSystemB subsystemB;
  20.     public Facade()
  21.     {
  22.         subsystemA = new SubSystemA();
  23.         subsystemB = new SubSystemB();
  24.     }
  25.     public void MethodA()
  26.     {
  27.         subsystemA.MethodA();
  28.     }
  29.     public void MethodB()
  30.     {
  31.         subsystemB.MethodB();
  32.     }
  33. }
  34. public class Client
  35. {
  36.     public static void Main()
  37.     {
  38.         Facade facade = new Facade();
  39.         facade.MethodA();
  40.         facade.MethodB();
  41.     }
  42. }
复制代码
  在上面的示例中,SubSystemA 和 SubSystemB 是两个子系统,它们分别实现了一些具体的功能。Facade 是外观类,它封装了对子系统的调用,并提供了一个简单的接口。Client 是客户端类,它通过调用 Facade 的方法来使用子系统的功能。   通过使用外观模式,我们可以将子系统的复杂逻辑封装在外观类中,使得客户端无需了解子系统的内部细节,只需要调用外观类的方法即可。这样可以降低子系统与客户端之间的耦合度,提高代码的可维护性和可扩展性。同时,外观类还可以提供一些额外的功能,例如对多个子系统的调用进行封装、提供一些公共的方法等。  11、享元模式(Flyweight Pattern):通过共享已有的对象减少对象的数量。
享元模式是一种结构型设计模式,它通过共享已有的对象来减少对象的创建数量,从而提高系统的性能和内存利用率。 享元模式的优点和缺点如下: 优点: 缺点: 综上所述,享元模式在实际项目中可以提供减少对象的创建数量、提高系统的可扩展性、减少代码的重复以及提高代码的可读性和可维护性等优点,但也可能导致增加代码的复杂性、对象的状态不一致、影响性能以及难以测试等缺点。在使用享元模式时,需要根据具体情况进行权衡和选择。  以下是一些常见的应用场景: 总之,享元模式可以在许多场景中使用,它通过共享对象的方式来减少对象的创建数量,从而提高系统的性能和内存利用率。在实际应用中,需要根据具体的业务场景来选择合适的享元模式实现方式。    下面是一个简单的 C# 实现享元模式的示例: 查看代码
  1.  using System;
  2. class Flyweight
  3. {
  4.     public virtual void Operation()
  5.     {
  6.         Console.WriteLine("这是一个普通的享元对象");
  7.     }
  8. }
  9. class FlyweightFactory
  10. {
  11.     private static Dictionary<int, Flyweight> flyweights = new Dictionary<int, Flyweight>();
  12.     public static Flyweight GetFlyweight(int key)
  13.     {
  14.         if (!flyweights.ContainsKey(key))
  15.         {
  16.             flyweights[key] = new ConcreteFlyweight(key);
  17.         }
  18.         return flyweights[key];
  19.     }
  20. }
  21. class ConcreteFlyweight : Flyweight
  22. {
  23.     private int key;
  24.     public ConcreteFlyweight(int key)
  25.     {
  26.         this.key = key;
  27.     }
  28.     public override void Operation()
  29.     {
  30.         Console.WriteLine($"这是一个具体的享元对象,其键值为 {key}");
  31.     }
  32. }
  33. class Program
  34. {
  35.     static void Main()
  36.     {
  37.         FlyweightFactory.GetFlyweight(1).Operation();
  38.         FlyweightFactory.GetFlyweight(2).Operation();
  39.     }
  40. }
复制代码
12、代理模式(Proxy Pattern):为一个对象提供一个代理,以控制对该对象的访问。
  代理模式是一种结构型设计模式,它允许一个类代表另一个类进行操作。这种模式通常用于在不同的层次之间进行通信或提供额外的功能,同时隐藏实际类的实现细节。   代理模式的优点和缺点如下: 优点: 缺点: 它可以在许多场景中使用,以下是一些常见的应用场景:  代理模式可以分为静态代理和动态代理两种类型。
静态代理模式是一种常见的代理模式,它通过创建一个代理类来对目标类的方法进行拦截和增强。
下面是一个简单的示例,演示如何使用 C# 实现静态代理模式:
查看代码
  1.  using System;
  2. public interface ISubject
  3. {
  4.     void Method();
  5. }
  6. public class RealSubject : ISubject
  7. {
  8.     public void Method()
  9.     {
  10.         Console.WriteLine("RealSubject.Method() called.");
  11.     }
  12. }
  13. public class ProxySubject : ISubject
  14. {
  15.     private readonly ISubject _subject;
  16.     public ProxySubject(ISubject subject)
  17.     {
  18.         _subject = subject;
  19.     }
  20.     public void Method()
  21.     {
  22.         Console.WriteLine("ProxySubject.Method() called before calling RealSubject.Method().");
  23.         _subject.Method();
  24.         Console.WriteLine("ProxySubject.Method() called after calling RealSubject.Method().");
  25.     }
  26. }
  27. public class Client
  28. {
  29.     public static void Main()
  30.     {
  31.         ISubject subject = new ProxySubject(new RealSubject());
  32.         subject.Method();
  33.     }
  34. }
复制代码
在上面的示例中,ISubject是一个接口,定义了一个方法Method()。RealSubject是实际类,实现了ISubject接口并实现了Method()方法。ProxySubject是代理类,也实现了ISubject接口,并在Method()方法中进行了拦截和增强。在ProxySubject的构造函数中,我们传入了实际类的实例,然后在Method()方法中首先输出一条消息,然后调用实际类的Method()方法,最后输出另一条消息。在Client类的Main()方法中,我们创建了一个代理类的实例,并调用其Method()方法。由于代理类实现了ISubject接口,因此可以将其作为实际类的类型进行传递。 运行上述代码,输出结果为: 查看代码
  1.  ProxySubject.Method() called before calling RealSubject.Method().
  2. RealSubject.Method() called.
  3. ProxySubject.Method() called after calling RealSubject.Method().
复制代码
  可以看到,代理类在调用实际类的方法之前和之后分别输出了一条消息,实现了对实际类方法的拦截和增强。通过使用代理类,我们可以在不修改实际类的情况下扩展系统的功能。   动态代理模式是一种在运行时创建代理类的代理模式。在 C# 中,可以使用System.Reflection命名空间提供的反射机制来实现动态代理模式。 下面是一个简单的示例,演示如何使用 C# 实现动态代理模式: 查看代码
  1.  using System;
  2. using System.Reflection;
  3. public interface ISubject
  4. {
  5.     void Method();
  6. }
  7. public class RealSubject : ISubject
  8. {
  9.     public void Method()
  10.     {
  11.         Console.WriteLine("RealSubject.Method() called.");
  12.     }
  13. }
  14. public class ProxyFactory
  15. {
  16.     public static ISubject CreateProxy(ISubject subject)
  17.     {
  18.         Type interfaceType = typeof(ISubject);
  19.         Type proxyType = Assembly.GetExecutingAssembly().GetType("DynamicProxy");
  20.         ConstructorInfo constructor = proxyType.GetConstructors()[0];
  21.         object[] args = { subject };
  22.         ISubject proxy = (ISubject)constructor.Invoke(args);
  23.         return proxy;
  24.     }
  25. }
  26. public class DynamicProxy : ISubject
  27. {
  28.     private readonly ISubject _subject;
  29.     public DynamicProxy(ISubject subject)
  30.     {
  31.         _subject = subject;
  32.     }
  33.     public void Method()
  34.     {
  35.         Console.WriteLine("ProxySubject.Method() called before calling RealSubject.Method().");
  36.         _subject.Method();
  37.         Console.WriteLine("ProxySubject.Method() called after calling RealSubject.Method().");
  38.     }
  39. }
  40. public class Client
  41. {
  42.     public static void Main()
  43.     {
  44.         ISubject subject = new RealSubject();
  45.         ISubject proxy = ProxyFactory.CreateProxy(subject);
  46.         proxy.Method();
  47.     }
  48. }
复制代码
在上面的示例中,ISubject是一个接口,定义了一个方法Method()。RealSubject是实际类,实现了ISubject接口并实现了Method()方法。ProxyFactory类是一个工厂类,用于创建动态代理类的实例。DynamicProxy是代理类,也实现了ISubject接口,并在Method()方法中进行了拦截和增强。在ProxyFactory类的CreateProxy()方法中,我们使用反射机制获取代理类的类型,并使用该类型创建一个实例。然后,我们将实际类的实例作为参数传递给代理类的构造函数,并返回代理类的实例。在DynamicProxy类中,我们通过构造函数获取实际类的实例,并在Method()方法中首先输出一条消息,然后调用实际类的Method()方法,最后输出另一条消息。在Client类的Main()方法中,我们创建了一个实际类的实例,并使用ProxyFactory类创建了一个代理类的实例。然后,我们调用代理类的Method()方法。 运行上述代码,输出结果为: 查看代码
  1.  ProxySubject.Method() called before calling RealSubject.Method().
  2. RealSubject.Method() called.
  3. ProxySubject.Method() called after calling RealSubject.Method().
复制代码
可以看到,代理类在调用实际类的方法之前和之后分别输出了一条消息,实现了对实际类方法的拦截和增强。通过使用动态代理模式,我们可以在不修改实际类的情况下扩展系统的功能。
   13、责任链模式(Chain of Responsibility Pattern):将多个对象练成一条责任链,并在链上传递请求。
  责任链模式是一种行为型设计模式,用于处理请求或事件在多个对象之间传递的情况。它将请求沿着一个链传递,每个对象都有机会处理该请求,如果某个对象无法处理该请求,则将其传递给下一个对象,直到有对象能够处理该请求为止。 责任链模式的优点和缺点如下: 优点: 缺点: 责任链模式适用于需要在多个对象之间传递请求或事件的场景,例如在框架中处理请求、在游戏中处理事件等。在实际应用中,需要根据具体的需求和场景选择合适的实现方式,并注意处理性能和异常情况。  责任链模式适用于以下场景:   总之,责任链模式适用于需要在多个对象之间传递请求或事件的场景,可以简化请求或事件的处理过程,提高系统的灵活性、可扩展性和处理性能。在实际应用中,需要根据具体的需求和场景选择合适的实现方式,并注意处理性能和异常情况。   以下是一个使用 C# 实现责任链模式的示例代码: 查看代码
  1.  using System;
  2. public interface IRequestHandler
  3. {
  4.     void HandleRequest(Request request);
  5. }
  6. public class Request
  7. {
  8.     public string Name { get; set; }
  9. }
  10. public class DefaultRequestHandler : IRequestHandler
  11. {
  12.     public void HandleRequest(Request request)
  13.     {
  14.         Console.WriteLine($"DefaultRequestHandler: Handling request {request.Name}");
  15.     }
  16. }
  17. public class SpecialRequestHandler : IRequestHandler
  18. {
  19.     public void HandleRequest(Request request)
  20.     {
  21.         Console.WriteLine($"SpecialRequestHandler: Handling request {request.Name}");
  22.     }
  23. }
  24. public class ChainRequestHandler
  25. {
  26.     private IRequestHandler[] handlers;
  27.     public ChainRequestHandler(params IRequestHandler[] handlers)
  28.     {
  29.         this.handlers = handlers;
  30.     }
  31.     public void HandleRequest(Request request)
  32.     {
  33.         foreach (IRequestHandler handler in handlers)
  34.         {
  35.             if (handler != null)
  36.             {
  37.                 handler.HandleRequest(request);
  38.             }
  39.         }
  40.     }
  41. }
  42. public class Program
  43. {
  44.     public static void Main()
  45.     {
  46.         var request = new Request { Name = "Test Request" };
  47.         var chain = new ChainRequestHandler(new DefaultRequestHandler(), new SpecialRequestHandler());
  48.         chain.HandleRequest(request);
  49.     }
  50. }
复制代码
  在上述示例中,我们定义了一个 IRequestHandler 接口,用于处理请求。然后,我们实现了两个具体的请求处理类 DefaultRequestHandler 和 SpecialRequestHandler,它们分别处理不同类型的请求。ChainRequestHandler 类是责任链模式的核心,它包含一个请求处理链,由多个 IRequestHandler 实例组成。ChainRequestHandler 类的 HandleRequest 方法遍历请求处理链中的每个请求处理器,并调用其 HandleRequest 方法处理请求。在 Program 类中,我们创建了一个请求对象 request,并创建了一个包含 DefaultRequestHandler 和 SpecialRequestHandler 的请求处理链 chain。然后,我们调用 chain.HandleRequest 方法处理请求。   运行程序后,将输出以下结果: 查看代码
  1.  DefaultRequestHandler: Handling request Test Request
  2. SpecialRequestHandler: Handling request Test Request
复制代码
  这表示请求被传递给了请求处理链中的每个请求处理器,并分别进行了处理。
    14、命令模式(Command Pattern):将一个请求封装为一个命令对象,并提供执行该命令的方法。
  命令模式是一种行为型设计模式,它将请求封装成一个对象,并提供一个统一的接口来执行请求。命令模式可以将请求的发起者和请求的执行者解耦,提高代码的灵活性和可扩展性。   在命令模式中,有以下几个主要角色:   责任链模式的优点和缺点如下:
  优点:   缺点:   综上所述,在实际项目中使用命令模式时,需要权衡其优缺点,根据具体的需求和场景来选择是否使用命令模式。如果需要解耦请求的发起者和请求的执行者,提高代码的灵活性和可扩展性,并且可以接受一定程度的复杂性增加,那么命令模式是一个不错的选择。    命令模式主要应用于以下场景:   总之,命令模式适用于需要对请求进行封装、组合、撤销和重做等操作的场景,可以提高代码的灵活性、可扩展性和可维护性。  下面是一个使用命令模式的示例代码: 查看代码
  1.  using System;
  2. public interface ICommand
  3. {
  4.     void Execute();
  5. }
  6. public class OpenFileCommand : ICommand
  7. {
  8.     private string filePath;
  9.     public OpenFileCommand(string filePath)
  10.     {
  11.         this.filePath = filePath;
  12.     }
  13.     public void Execute()
  14.     {
  15.         Console.WriteLine($"Opening file: {filePath}");
  16.     }
  17. }
  18. public class SaveFileCommand : ICommand
  19. {
  20.     private string filePath;
  21.     public SaveFileCommand(string filePath)
  22.     {
  23.         this.filePath = filePath;
  24.     }
  25.     public void Execute()
  26.     {
  27.         Console.WriteLine($"Saving file: {filePath}");
  28.     }
  29. }
  30. public class FileInvoker
  31. {
  32.     private ICommand[] commands;
  33.     public FileInvoker(params ICommand[] commands)
  34.     {
  35.         this.commands = commands;
  36.     }
  37.     public void ExecuteCommands()
  38.     {
  39.         foreach (ICommand command in commands)
  40.         {
  41.             command.Execute();
  42.         }
  43.     }
  44. }
  45. public class Program
  46. {
  47.     public static void Main()
  48.     {
  49.         var invoker = new FileInvoker(new OpenFileCommand("example.txt"), new SaveFileCommand("example.txt"));
  50.         invoker.ExecuteCommands();
  51.     }
  52. }
复制代码
  在上述示例中,我们定义了一个 ICommand 接口,用于执行请求。然后,我们实现了两个具体的命令 OpenFileCommand 和 SaveFileCommand,它们分别执行打开文件和保存文件的操作。FileInvoker 类是命令的调用者,它包含一个命令数组,并提供了一个 ExecuteCommands 方法来执行命令。在 Program 类中,我们创建了一个 FileInvoker 对象,并向其中添加了两个命令。然后,我们调用 ExecuteCommands 方法执行命令。 运行程序后,将输出以下结果: 查看代码
  1.  Opening file: example.txt
  2. Saving file: example.txt
复制代码
  这表示命令被成功执行,打开并保存了文件。通过使用命令模式,我们将请求的发起者和请求的执行者解耦,提高了代码的灵活性和可扩展性。
   15、解释器模式(Interprter Pattern):提供一个解释器,用于解释特定的语言或语法。
  解释器模式是一种行为型设计模式,它定义了一个语言的语法规则,并提供了一个解释器来解释和执行该语言的语句。   解释器模式的主要作用是将一个高级语言或语法规则解释成低级的操作或指令。解释器模式通过定义一个抽象的解释器类,以及一系列具体的解释器类来实现对不同语言或语法规则的解释。   解释器模式的优点和缺点如下:   优点:
  缺点:   综上所述,解释器模式适用于需要对复杂的语法规则进行解释和执行的场景,可以提高代码的可读性、可理解性和灵活性。但是,解释器模式的实现较为复杂,可能会导致性能问题和可读性、可维护性较差的问题,因此在实际应用中需要根据具体情况进行选择。    主要应用于以下场景:   总之,解释器模式适用于需要对复杂的语法规则进行解释和执行的场景,可以提高代码的可读性、可理解性和灵活性。但是,解释器模式的实现较为复杂,可能会导致性能问题和可读性、可维护性较差的问题,因此在实际应用中需要根据具体情况进行选择。   以下是一个使用 C#实现解释器模式的示例,它演示了如何解释一个简单的数学表达式。 查看代码
  1.  using System;
  2. public class Expression
  3. {
  4.     public virtual void Interpret(Context context)
  5.     {
  6.         throw new NotImplementedException();
  7.     }
  8. }
  9. public class Context
  10. {
  11.     public decimal Number { get; set; }
  12. }
  13. public class AddExpression : Expression
  14. {
  15.     private Expression left;
  16.     private Expression right;
  17.     public AddExpression(Expression left, Expression right)
  18.     {
  19.         this.left = left;
  20.         this.right = right;
  21.     }
  22.     public override void Interpret(Context context)
  23.     {
  24.         left.Interpret(context);
  25.         right.Interpret(context);
  26.         context.Number = context.Number + right.Context.Number;
  27.     }
  28. }
  29. public class SubtractExpression : Expression
  30. {
  31.     private Expression left;
  32.     private Expression right;
  33.     public SubtractExpression(Expression left, Expression right)
  34.     {
  35.         this.left = left;
  36.         this.right = right;
  37.     }
  38.     public override void Interpret(Context context)
  39.     {
  40.         left.Interpret(context);
  41.         right.Interpret(context);
  42.         context.Number = context.Number - right.Context.Number;
  43.     }
  44. }
  45. public class MultiplyExpression : Expression
  46. {
  47.     private Expression left;
  48.     private Expression right;
  49.     public MultiplyExpression(Expression left, Expression right)
  50.     {
  51.         this.left = left;
  52.         this.right = right;
  53.     }
  54.     public override void Interpret(Context context)
  55.     {
  56.         left.Interpret(context);
  57.         right.Interpret(context);
  58.         context.Number = context.Number * right.Context.Number;
  59.     }
  60. }
  61. public class DivideExpression : Expression
  62. {
  63.     private Expression left;
  64.     private Expression right;
  65.     public DivideExpression(Expression left, Expression right)
  66.     {
  67.         this.left = left;
  68.         this.right = right;
  69.     }
  70.     public override void Interpret(Context context)
  71.     {
  72.         left.Interpret(context);
  73.         right.Interpret(context);
  74.         context.Number = context.Number / right.Context.Number;
  75.     }
  76. }
  77. public class Program
  78. {
  79.     public static void Main()
  80.     {
  81.         Context context = new Context();
  82.         Expression expression = new AddExpression(new SubtractExpression(new MultiplyExpression(new Number(5), new Number(3)), new Number(2)), new Number(4));
  83.         expression.Interpret(context);
  84.         Console.WriteLine(context.Number);
  85.     }
  86. }
复制代码
  在这个示例中,我们定义了一个表达式类Expression,它是解释器模式的抽象基类。我们还定义了一个上下文类Context,用于存储解释器的状态。然后,我们定义了四个具体的表达式类:AddExpression、SubtractExpression、MultiplyExpression和DivideExpression,它们分别表示加法、减法、乘法和除法运算。在Program类的Main方法中,我们创建了一个上下文对象context,并创建了一个表达式对象expression,它表示一个包含了多个运算的数学表达式。然后,我们调用expression.Interpret方法解释这个表达式,并将结果存储在上下文对象中。最后,我们输出解释后的结果。   这个示例演示了如何使用解释器模式解释一个简单的数学表达式。解释器模式将语法规则和解释过程分离,使得代码更加清晰和易于维护。   16、迭代器模式(Iterator Pattern):提供一种遍历集合元素的方式,而不暴露集合的内部结构。
  迭代器模式是一种行为型设计模式,用于提供一种按顺序访问聚合对象中元素的方法,而无需暴露该聚合对象的内部结构。这种模式可以用于各种编程语言和应用场景,例如 C++、C#、Java、Python 等。   迭代器模式的核心思想是将聚合对象的遍历操作封装在一个迭代器对象中,该迭代器对象提供了遍历聚合对象的方法,并隐藏了聚合对象的内部结构。这样可以使得聚合对象的使用者只需要关注迭代器对象的方法,而无需关心聚合对象的内部实现。   迭代器模式的主要角色包括:   下面是迭代器模式的类图: 查看代码
  1.  class Iterator {
  2.     interface method Next();
  3.     interface method IsDone();
  4. }
  5. class Aggregate {
  6.     method CreateIterator() : Iterator;
  7. }
  8. class ConcreteAggregate {
  9.     method CreateIterator() : ConcreteIterator;
  10. }
  11. class ConcreteIterator implements Iterator {
  12.     method Next() { ... }
  13.     method IsDone() { ... }
  14. }
复制代码
  在上面的类图中,Iterator是迭代器的抽象类,定义了遍历聚合对象元素的接口方法Next()和IsDone()。Aggregate是聚合对象的抽象类,定义了创建迭代器的方法CreateIterator()。ConcreteAggregate是具体聚合对象的类,实现了CreateIterator()方法,返回具体迭代器的实例。ConcreteIterator是具体迭代器的类,实现了Iterator接口,提供了遍历具体聚合对象元素的方法。   通过使用迭代器模式,我们可以在不暴露聚合对象内部结构的情况下,提供一种按顺序访问聚合对象中元素的方法。同时,迭代器模式还可以提供一种统一的遍历方式,使得我们可以在不同的聚合对象之间复用迭代器对象,提高了代码的可复用性和可维护性。    迭代器模式具有以下优点和缺点:   优点:   缺点:   迭代器模式通常适用于以下场景:      在 C#中,可以通过实现IEnumerator接口来实现迭代器模式。   下面是一个简单的示例,演示如何使用迭代器模式来遍历一个整数列表: 查看代码
  1.  using System;
  2. using System.Collections;
  3. class IntegerList : IEnumerable
  4. {
  5.     private List<int> list = new List<int>();
  6.     public IEnumerator GetEnumerator()
  7.     {
  8.         return new IntegerEnumerator(list);
  9.     }
  10.     public void Add(int value)
  11.     {
  12.         list.Add(value);
  13.     }
  14. }
  15. class IntegerEnumerator : IEnumerator
  16. {
  17.     private List<int> list;
  18.     private int position = -1;
  19.     public IntegerEnumerator(List<int> list)
  20.     {
  21.         this.list = list;
  22.     }
  23.     public object Current
  24.     {
  25.         get
  26.         {
  27.             if (position < list.Count - 1)
  28.             {
  29.                 return list[position + 1];
  30.             }
  31.             else
  32.             {
  33.                 throw new InvalidOperationException("No more elements.");
  34.             }
  35.         }
  36.     }
  37.     public bool MoveNext()
  38.     {
  39.         if (position < list.Count - 1)
  40.         {
  41.             position++;
  42.             return true;
  43.         }
  44.         else
  45.         {
  46.             return false;
  47.         }
  48.     }
  49.     public void Reset()
  50.     {
  51.         position = -1;
  52.     }
  53. }
复制代码
   在上面的示例中,IntegerList类是聚合对象,它包含一个整数列表。GetEnumerator方法返回一个迭代器对象,该对象实现了IEnumerator接口。IntegerEnumerator类是具体迭代器,它实现了IEnumerator接口的方法,用于遍历整数列表中的元素。   17、中介者模式(Mediator Pattern):使用一个中介者对象来协调多个对象之间的通信。
  中介者模式是一种行为型设计模式,它定义了一个中介者类来协调多个对象之间的交互。这些对象通过与中介者类进行通信,而不是直接相互通信,从而降低了对象之间的耦合度。
  中介者模式的结构如下:   中介者模式的优点和缺点如下:   优点:
  缺点:   中介者模式适用于需要协调多个对象之间的交互,降低对象之间的耦合度,提高代码的可复用性和可维护性的场景。例如,在多个对象之间需要进行通信的分布式系统中,中介者模式可以提供一种统一的交互方式,降低对象之间的耦合度,提高系统的可扩展性和可靠性。    中介者模式通常适用于以下场景: 以下是一些常见的中介者模式的应用场景:   总之,中介者模式可以通过引入中介者对象来简化对象之间的通信和协作,提高系统的可靠性和可维护性。在实际应用中,需要根据具体的场景和需求来选择合适的中介者模式的实现方式。    下面是一个使用 C# 实现中介者模式的示例:
  查看代码
  1.  using System;
  2. public class Mediator
  3. {
  4.     private string message;
  5.     public void SendMessage(string message)
  6.     {
  7.         this.message = message;
  8.         Console.WriteLine("发送消息:" + message);
  9.     }
  10.     public void SendMessageToAllListeners()
  11.     {
  12.         foreach (var listener in Listeners)
  13.         {
  14.             listener.ReceiveMessage(message);
  15.         }
  16.     }
  17.     public void RegisterListener(IListener listener)
  18.     {
  19.         Listeners.Add(listener);
  20.     }
  21.     private List<IListener> Listeners = new List<IListener>();
  22. }
  23. public interface IListener
  24. {
  25.     void ReceiveMessage(string message);
  26. }
  27. public class ConcreteListener1 : IListener
  28. {
  29.     public void ReceiveMessage(string message)
  30.     {
  31.         Console.WriteLine(" ConcreteListener1 收到消息:" + message);
  32.     }
  33. }
  34. public class ConcreteListener2 : IListener
  35. {
  36.     public void ReceiveMessage(string message)
  37.     {
  38.         Console.WriteLine("ConcreteListener2 收到消息:" + message);
  39.     }
  40. }
  41. public class Program
  42. {
  43.     public static void Main()
  44.     {
  45.         var mediator = new Mediator();
  46.         var listener1 = new ConcreteListener1();
  47.         var listener2 = new ConcreteListener2();
  48.         mediator.RegisterMessage(listener1);
  49.         mediator.RegisterMessage(listener2);
  50.         mediator.SendMessage("这是一条消息");
  51.         Console.ReadLine();
  52.     }
  53. }
复制代码
  在上述示例中,Mediator 类是中介者模式的核心,它负责管理所有的监听者并在需要时通知它们。SendMessage 方法用于发送消息,RegisterListener 方法用于注册监听者,SendMessageToAllListeners 方法用于向所有监听者发送消息。IListener 接口是监听者的抽象接口,它定义了一个ReceiveMessage方法用于处理接收到的消息。ConcreteListener1和ConcreteListener2是具体的监听者实现,它们实现了IListener接口并处理接收到的消息。在Main方法中,我们创建了一个Mediator对象,并注册了两个监听者。然后,我们调用SendMessage方法发送一条消息,中介者会将消息转发给所有注册的监听者。   需要注意的是,中介者模式的实现方式可以根据具体的需求和场景进行调整。例如,中介者可以管理多个主题或事件,并根据需要通知相应的监听者。监听者也可以注册对特定主题或事件的兴趣,并只接收感兴趣的消息。 18、备忘录模式(Memento Pattern):保存一个对象的状态,以便在需要时恢复该状态。
  备忘录模式是一种行为型软件设计模式,它提供了一种在不破坏对象封装性的前提下,捕获和保存对象状态的方法。备忘录模式允许在需要时恢复对象的先前状态,从而实现了撤销操作。   备忘录模式的核心思想是使用一个备忘录类来保存对象的状态信息。备忘录类是一个独立的类,它包含了对象的状态信息,并提供了一个方法来恢复对象的状态。备忘录类通常被设计成不可变的,以确保对象的状态不会被意外地修改。   备忘录模式包含三个主要角色:   备忘录模式的优点和缺点如下:   优点:
  缺点:   因此,在使用备忘录模式时,需要权衡其优缺点,并根据具体的应用场景和需求来选择是否使用备忘录模式。    备忘录模式可以应用于以下场景:   总之,备忘录模式可以应用于需要保存对象状态、提供撤销操作、回滚操作、恢复操作、状态管理、历史记录、数据备份和错误恢复等场景。   下面是一个使用 C# 实现备忘录模式的示例:    查看代码
  1.  using System;
  2. class Memento {
  3.     public string State { get; set; }
  4. }
  5. class Originator {
  6.     public string State { get; set; }
  7.     public Memento CreateMemento() {
  8.         return new Memento { State = State };
  9.     }
  10.     public void SetMemento(Memento memento) {
  11.         State = memento.State;
  12.     }
  13. }
  14. class CareTaker {
  15.     public Memento Memento { get; set; }
  16.     public void SetMemento(Memento memento) {
  17.         this.Memento = memento;
  18.     }
  19. }
  20. class Program {
  21.     static void Main() {
  22.         Originator originator = new Originator();
  23.         originator.State = "State 1";
  24.         CareTaker careTaker = new CareTaker();
  25.         careTaker.SetMemento(originator.CreateMemento());
  26.         originator.State = "State 2";
  27.         careTaker.Memento = originator.CreateMemento();
  28.         originator.SetMemento(careTaker.Memento);
  29.         Console.WriteLine(originator.State);  // State 1
  30.     }
  31. }
复制代码
  在上述示例中,Originator 类表示需要保存状态的对象,Memento 类表示保存状态的备忘录对象,CareTaker 类表示保存备忘录对象的管理者。在 Main 方法中,我们创建了一个 Originator 对象并设置其状态为 "State 1",然后将其备忘录对象保存到 CareTaker 对象中。接着,我们修改 Originator 对象的状态为 "State 2",并再次保存其备忘录对象到 CareTaker 对象中。最后,我们通过 Originator 对象的 SetMemento 方法恢复其状态为 "State 1"。   19、观察者模式(Observer Pattern):定义一个对象和多个观察者之间的一对多依赖关系。
  观察者模式是一种行为型软件设计模式,用于建立一种对象与对象之间的依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都将得到通知并自动更新。   观察者模式包含以下角色:   观察者模式的工作原理如下:   观察者模式可以实现解耦,使被观察者和观察者之间不存在直接的依赖关系,从而提高了系统的可扩展性和可维护性。同时,观察者模式还可以支持多个观察者同时订阅同一个被观察者,实现了广播机制。    观察者模式优点和缺点如下:   优点:   缺点:   总的来说,观察者模式是一种非常有用的设计模式,可以实现对象之间的解耦和广播机制,提高系统的可扩展性和可维护性。但是,在使用观察者模式时,需要注意处理好依赖关系和性能问题,并确保通知机制的简单性和可读性。     观察者模式可以用于以下场景:   总的来说,观察者模式可以用于需要实现事件通知、数据更新、消息传递、状态监控和数据绑定等场景。它可以帮助我们实现对象之间的解耦,提高系统的可扩展性和可维护性。      下面是一个使用 C# 实现观察者模式的示例:  查看代码
  1.  using System;
  2. class Observer {
  3.     public void Update() {
  4.         Console.WriteLine("Observer received notification.");
  5.     }
  6. }
  7. class Subject {
  8.     private List<Observer> observers = new List<Observer>();
  9.     public void RegisterObserver(Observer observer) {
  10.         observers.Add(observer);
  11.     }
  12.     public void UnregisterObserver(Observer observer) {
  13.         observers.Remove(observer);
  14.     }
  15.     public void NotifyObservers() {
  16.         foreach (Observer observer in observers) {
  17.             observer.Update();
  18.         }
  19.     }
  20. }
  21. class Program {
  22.     static void Main() {
  23.         Subject subject = new Subject();
  24.         Observer observer1 = new Observer();
  25.         Observer observer2 = new Observer();
  26.         subject.RegisterObserver(observer1);
  27.         subject.RegisterObserver(observer2);
  28.         subject.NotifyObservers();  // Observer1 and Observer2 will receive notification.
  29.         subject.UnregisterObserver(observer1);
  30.         subject.NotifyObservers();  // Only Observer2 will receive notification.
  31.     }
  32. }
复制代码
  在上述示例中,Subject 类表示被观察者,Observer 类表示观察者,RegisterObserver 方法用于注册观察者,UnregisterObserver 方法用于注销观察者,NotifyObservers 方法用于向所有注册的观察者发布通知。通过使用观察者模式,我们可以实现对象之间的解耦,提高系统的可扩展性和可维护性。
  20、状态模式(State Pattern):将一个对象的状态封装在不同的状态类中,并提供状态转换的方法。
  状态模式是一种行为型设计模式,它允许对象在不同状态之间进行切换,并根据当前状态执行不同的行为。状态模式将状态和行为封装在一起,并通过状态转移来改变对象的行为。在状态模式中,一个对象具有多个状态,每个状态对应一个特定的行为。状态模式通过将状态和行为封装在状态类中,并将状态的切换逻辑封装在状态管理器中,从而实现了对象在不同状态之间的切换。   状态模式的优点和缺点如下:   优点:   缺点:   总的来说,状态模式是一种非常有用的设计模式,它可以帮助我们实现对象在不同状态之间的切换,并根据当前状态执行不同的行为。但是,在使用状态模式时,需要注意处理好状态数量过多的问题,并确保状态切换逻辑的清晰和易于维护。    以下是状态模式的一些应用场景:   总的来说,状态模式可以用于需要管理对象状态并根据状态执行不同操作的场景。通过使用状态模式,可以将状态和行为封装在状态类中,并通过状态管理器来管理状态的切换,从而提高代码的可维护性和可扩展性。   下面是一个使用 C# 实现状态模式的示例代码:  查看代码
  1.  using System;
  2. public class State
  3. {
  4.     public virtual void Handle()
  5.     {
  6.         Console.WriteLine("默认状态");
  7.     }
  8. }
  9. public class StateA : State
  10. {
  11.     public override void Handle()
  12.     {
  13.         Console.WriteLine("状态 A");
  14.     }
  15. }
  16. public class StateB : State
  17. {
  18.     public override void Handle()
  19.     {
  20.         Console.WriteLine("状态 B");
  21.     }
  22. }
  23. public class StateContext
  24. {
  25.     private State _state;
  26.     public StateContext()
  27.     {
  28.         _state = new State();
  29.     }
  30.     public void ChangeStateA()
  31.     {
  32.         _state = new StateA();
  33.     }
  34.     public void ChangeStateB()
  35.     {
  36.         _state = new StateB();
  37.     }
  38.     public void Handle()
  39.     {
  40.         _state.Handle();
  41.     }
  42. }
  43. class Program
  44. {
  45.     static void Main()
  46.     {
  47.         StateContext context = new StateContext();
  48.         context.Handle();  // 输出:默认状态
  49.         context.ChangeStateA();
  50.         context.Handle();  // 输出:状态 A
  51.         context.ChangeStateB();
  52.         context.Handle();  // 输出:状态 B
  53.     }
  54. }
复制代码
  在上述示例中,我们定义了一个State抽象类,它包含一个Handle方法,用于处理当前状态下的操作。然后,我们定义了两个具体的状态类StateA和StateB,它们分别实现了Handle方法来处理不同的状态。StateContext类是状态模式的核心,它维护了一个当前状态的引用,并提供了方法来切换状态。在Handle方法中,它会调用当前状态的Handle方法来执行相应的操作。 在Main方法中,我们创建了一个StateContext对象,并通过调用ChangeStateA和ChangeStateB方法来切换状态。最后,我们调用Handle方法来处理当前状态下的操作,并输出相应的状态信息。   这是一个简单的状态模式实现,你可以根据具体的需求进行扩展和修改。通过使用状态模式,我们可以将状态和行为封装在状态类中,并通过状态管理器来管理状态的切换,从而提高代码的可维护性和可扩展性。   21、策略模式(Strategy Pattern):定义一组算法,并将其封装在不同的策略类中,以便在不同的上下文中使用。
  策略模式让算法的变化独立于使用它们的客户端。在策略模式中,通常包含以下三个角色:
  策略模式的优点和缺点如下:   优点:
  缺点:   策略模式的一些应用场景:   总的来说,策略模式适用于需要根据不同的条件或需求选择不同算法的场景,它可以提高代码的可读性、可维护性和可扩展性。   下面是一个简单的策略模式示例代码,演示了如何使用策略模式来实现不同的计算方法:
  查看代码
  1.  using System;
  2. public interface ICalculate
  3. {
  4.     int Calculate(int a, int b);
  5. }
  6. public class Add : ICalculate
  7. {
  8.     public int Calculate(int a, int b)
  9.     {
  10.         return a + b;
  11.     }
  12. }
  13. public class Subtract : ICalculate
  14. {
  15.     public int Calculate(int a, int b)
  16.     {
  17.         return a - b;
  18.     }
  19. }
  20. public class Context
  21. {
  22.     private ICalculate _calculate;
  23.     public Context(ICalculate calculate)
  24.     {
  25.         _calculate = calculate;
  26.     }
  27.     public void SetCalculate(ICalculate calculate)
  28.     {
  29.         _calculate = calculate;
  30.     }
  31.     public int Calculate(int a, int b)
  32.     {
  33.         return _calculate.Calculate(a, b);
  34.     }
  35. }
  36. class Program
  37. {
  38.     static void Main()
  39.     {
  40.         Context context = new Context(new Add());
  41.         Console.WriteLine(context.Calculate(3, 4));  // 输出:7
  42.         context.SetCalculate(new Subtract());
  43.         Console.WriteLine(context.Calculate(3, 4));  // 输出:-1
  44.     }
  45. }
复制代码
  在上述示例中,我们定义了一个ICalculate接口,它包含一个Calculate方法。然后,我们实现了两个具体策略类Add和Subtract,它们分别实现了Calculate方法来执行加法和减法运算。Context类持有一个ICalculate对象的引用,并提供了一个方法来设置和获取当前使用的策略对象。在Calculate方法中,它调用当前策略对象的Calculate方法来执行相应的运算。 在Main方法中,我们创建了一个Context对象,并将其初始化为使用加法策略。然后,我们调用Calculate方法来计算 3 和 4 的和,并输出结果 7。接着,我们通过调用SetCalculate方法将策略切换为减法策略,并再次调用Calculate方法来计算 3 和 4 的差,并输出结果-1。   通过使用策略模式,我们可以根据需要动态地切换不同的计算方法,而不需要修改Context类的代码。这提高了代码的可维护性和可扩展性 22、模板方法模式(Template Method Pattern):定义一个模板方法,其中包含一些步骤的实现,并将这些步骤的实现延迟到子类中。
  模板方法模式是一种行为型设计模式,它定义了一个算法的步骤,并将其中一些步骤延迟到子类中实现。模板方法模式让子类可以在不改变算法结构的情况下重写某些步骤。    在模板方法模式中,有一个抽象类,它定义了一个算法的模板方法,该方法包含了算法的主要步骤,但其中一些步骤被声明为抽象方法。子类可以通过重写这些抽象方法来实现不同的算法步骤。   以下是模板方法模式的结构:   模板方法模式的优点和缺点如下:   优点:   缺点:   模板方法模式通常适用于以下场景:   总的来说,模板方法模式适用于需要提供一个通用的算法结构,并允许子类在不修改算法结构的情况下重写特定步骤的场景。通过使用模板方法模式,可以提高代码的复用性、可扩展性和封装性。   以下是一个使用 C# 实现模板方法模式的示例:    查看代码
  1.  using System;
  2. public abstract class TemplateMethod
  3. {
  4.     public void Algorithm()
  5.     {
  6.         Console.WriteLine("执行算法的初始步骤");
  7.         AbstractStep1();
  8.         Console.WriteLine("执行算法的中间步骤");
  9.         AbstractStep2();
  10.         Console.WriteLine("执行算法的结束步骤");
  11.     }
  12.     protected abstract void AbstractStep1();
  13.     protected abstract void AbstractStep2();
  14. }
  15. public class ConcreteClass1 : TemplateMethod
  16. {
  17.     protected override void AbstractStep1()
  18.     {
  19.         Console.WriteLine("具体类 1 的步骤 1");
  20.     }
  21.     protected override void AbstractStep2()
  22.     {
  23.         Console.WriteLine("具体类 1 的步骤 2");
  24.     }
  25. }
  26. public class ConcreteClass2 : TemplateMethod
  27. {
  28.     protected override void AbstractStep1()
  29.     {
  30.         Console.WriteLine("具体类 2 的步骤 1");
  31.     }
  32.     protected override void AbstractStep2()
  33.     {
  34.         Console.WriteLine("具体类 2 的步骤 2");
  35.     }
  36. }
  37. public class Program
  38. {
  39.     public static void Main()
  40.     {
  41.         Console.WriteLine("具体类 1 的执行结果:");
  42.         var obj1 = new ConcreteClass1();
  43.         obj1.Algorithm();
  44.         Console.WriteLine("\n具体类 2 的执行结果:");
  45.         var obj2 = new ConcreteClass2();
  46.         obj2.Algorithm();
  47.     }
  48. }
复制代码
  在上面的示例中,TemplateMethod 是抽象类,它定义了算法的整体结构和步骤。AbstractStep1 和 AbstractStep2 是抽象方法,需要子类实现。 ConcreteClass1 和 ConcreteClass2 是 TemplateMethod 的子类,它们分别实现了 AbstractStep1 和 AbstractStep2 方法,以提供具体的步骤实现。在 Main 方法中,我们创建了 ConcreteClass1 和 ConcreteClass2 的实例,并调用它们的 Algorithm 方法来执行算法。由于 Algorithm 方法的步骤是通过子类重写实现的,因此输出结果会因具体子类的不同而有所差异。  23、访问者模式(Visitor Pattern):定义一个访问者类,用于访问其他类中的元素,并提供同一的访问方式。
  访问者模式是一种行为型设计模式,它允许在不修改现有类结构的情况下,通过添加新的访问者类来对现有类的结构进行扩展。访问者模式将数据结构与对数据结构的操作分离开来,使得可以在不改变数据结构的情况下添加新的操作。   在访问者模式中,存在一个 Visitor 类和一个 Element 类。Element 类表示要被访问的数据结构中的元素,它包含一个接受 Visitor 访问的方法。Visitor 类是一个抽象类,它定义了访问 Element 类的方法。具体的 Visitor 子类实现了这些方法,以对 Element 类进行具体的操作。    访问者模式的优点和缺点如下:   优点:   缺点:   以下是一些常见的访问者模式应用场景:   总的来说,访问者模式适用于需要对数据结构进行多种不同操作的场景,并且这些操作需要在不同的时间、地点或上下文环境中进行。通过使用访问者模式,可以将对数据结构的操作与数据结构本身分离,提高代码的可扩展性和可维护性。    下面是一个使用 C# 实现访问者模式的示例:  查看代码
  1.  using System;
  2. public interface IElement
  3. {
  4.     void Accept(IVisitor visitor);
  5. }
  6. public interface IVisitor
  7. {
  8.     void Visit(IElement element);
  9. }
  10. public class ConcreteElement1 : IElement
  11. {
  12.     public void Accept(IVisitor visitor)
  13.     {
  14.         visitor.Visit(this);
  15.     }
  16. }
  17. public class ConcreteElement2 : IElement
  18. {
  19.     public void Accept(IVisitor visitor)
  20.     {
  21.         visitor.Visit(this);
  22.     }
  23. }
  24. public class ConcreteVisitor1 : IVisitor
  25. {
  26.     public void Visit(IElement element)
  27.     {
  28.         Console.WriteLine("Visiting concreteElement1");
  29.     }
  30. }
  31. public class ConcreteVisitor2 : IVisitor
  32. {
  33.     public void Visit(IElement element)
  34.     {
  35.         Console.WriteLine("Visiting concreteElement2");
  36.     }
  37. }
  38. public class Program
  39. {
  40.     public static void Main()
  41.     {
  42.         var element1 = new ConcreteElement1();
  43.         var element2 = new ConcreteElement2();
  44.         var visitor1 = new ConcreteVisitor1();
  45.         var visitor2 = new ConcreteVisitor2();
  46.         element1.Accept(visitor1);
  47.         element2.Accept(visitor1);
  48.         element1.Accept(visitor2);
  49.         element2.Accept(visitor2);
  50.     }
  51. }
复制代码
  在上面的示例中,IElement 是一个表示元素的接口,它包含一个接受访问者的方法 Accept。IVisitor 是一个表示访问者的接口,它包含一个访问元素的方法 Visit。 ConcreteElement1 和 ConcreteElement2 是 IElement 的具体实现,它们表示不同的元素。ConcreteVisitor1 和 ConcreteVisitor2 是 IVisitor 的具体实现,它们表示不同的访问者。在 Main 方法中,我们创建了两个元素和两个访问者,并使用 Accept 方法将元素传递给访问者进行访问。由于访问者是通过多态方式实现的,因此可以使用不同的访问者对元素进行不同的操作。  这些设计模式在软件开发中非常常见,可以帮助开发人员解决许多常见的问题,并提高代码的可复用性、可维护性和可扩展性。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4