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

标题: 23种计划模式详解 [打印本页]

作者: 用户国营    时间: 2024-9-18 19:53
标题: 23种计划模式详解
23种计划模式详解


  
计划模式(Design Patterns)是软件工程中的一种办理方案,它提供了一套颠末验证的代码计划和架构方案,用于办理软件计划中反复出现的题目。计划模式不特定于某种编程语言,而是普遍适用于各种面向对象的编程语言。计划模式主要分为三大类:创建型模式、结构型模式和行为型模式。
1 计划模式概述

1.1 创建型模式(Creational Patterns)

创建型模式关注对象的创建过程,旨在使对象的创建与使用分离,避免体系与具体类之间的紧密耦合。

2.2 结构型模式(Structural Patterns)

结构型模式关注类和对象的组合,旨在通过组合接口和实现来实现新的功能。

3.3 行为型模式(Behavioral Patterns)

行为型模式关注对象之间的通信和职责分配,旨在进步对象之间的通信服从和灵活性。

2 计划模式详解

2.1 简单工厂模式(Simple Factory Pattern)

2.1.1 定义

简单工厂模式,也称为静态工厂方法模式,并不属于GoF(Gang of Four)计划模式之一。它提供了一个创建对象的简单接口,通过通报不同的参数来决定创建哪种类的实例。
2.1.2 结构

简单工厂模式包罗以下角色:

UML 类图
  1. +-------------------+
  2. |      Factory      |
  3. +-------------------+
  4. | + CreateProduct() |
  5. +-------------------+
  6.           |
  7.           v
  8. +-------------------+
  9. |    Product        |
  10. +-------------------+
  11.          / \
  12.         /   \
  13. +--------+ +---------+
  14. |ProductA| |ProductB |
  15. +--------+ +---------+
复制代码
2.1.3 示例代码

  1. // 产品接口
  2. public interface IProduct
  3. {
  4.     void Display();
  5. }
  6. // 具体产品A
  7. public class ProductA : IProduct
  8. {
  9.     public void Display()
  10.     {
  11.         Console.WriteLine("Product A");
  12.     }
  13. }
  14. // 具体产品B
  15. public class ProductB : IProduct
  16. {
  17.     public void Display()
  18.     {
  19.         Console.WriteLine("Product B");
  20.     }
  21. }
  22. // 简单工厂
  23. public class SimpleFactory
  24. {
  25.     public static IProduct CreateProduct(string type)
  26.     {
  27.         if (type == "A")
  28.         {
  29.             return new ProductA();
  30.         }
  31.         else if (type == "B")
  32.         {
  33.             return new ProductB();
  34.         }
  35.         else
  36.         {
  37.             throw new ArgumentException("Invalid type");
  38.         }
  39.     }
  40. }
  41. // 客户端代码
  42. class Program
  43. {
  44.     static void Main(string[] args)
  45.     {
  46.         IProduct product = SimpleFactory.CreateProduct("A");
  47.         product.Display();
  48.     }
  49. }
复制代码
2.1.4 特点


2.1.5 适用场景


2.1.6 工厂方法模式(Factory Method Pattern)

2.1.6.1 定义

工厂方法模式定义了一个用于创建对象的接口,但由子类决定实例化哪一个类。通过这种方式,工厂方法将对象的创建推迟到子类。
2.1.6.2 结构

工厂方法模式包罗以下角色:

UML 类图
  1.       +---------------------+
  2.       |     Creator         |
  3.       +---------------------+
  4.       | + FactoryMethod()   |
  5.       +---------------------+
  6.                |
  7.                |
  8.                v
  9.       +---------------------+
  10.       | ConcreteCreator      |
  11.       +---------------------+
  12.       | + FactoryMethod()    |
  13.       +---------------------+
  14.                |
  15.                |
  16.                v
  17.       +---------------------+
  18.       | ConcreteProduct      |
  19.       +---------------------+
  20.       | Implements Product   |
  21.       +---------------------+
复制代码
2.1.6.3 示例代码

假设我们要创建不同范例的日记记录器(如控制台日记记录器和文件日记记录器),可以使用工厂方法模式。
  1. // 产品接口
  2. public interface ILogger
  3. {
  4.     void Log(string message);
  5. }
  6. // 具体产品1:控制台日志记录器
  7. public class ConsoleLogger : ILogger
  8. {
  9.     public void Log(string message)
  10.     {
  11.         Console.WriteLine("Console Logger: " + message);
  12.     }
  13. }
  14. // 具体产品2:文件日志记录器
  15. public class FileLogger : ILogger
  16. {
  17.     public void Log(string message)
  18.     {
  19.         Console.WriteLine("File Logger: " + message);
  20.     }
  21. }
  22. // 抽象创建者
  23. public abstract class LoggerFactory
  24. {
  25.     public abstract ILogger CreateLogger();
  26.     public void WriteLog(string message)
  27.     {
  28.         var logger = CreateLogger();
  29.         logger.Log(message);
  30.     }
  31. }
  32. // 具体创建者1
  33. public class ConsoleLoggerFactory : LoggerFactory
  34. {
  35.     public override ILogger CreateLogger()
  36.     {
  37.         return new ConsoleLogger();
  38.     }
  39. }
  40. // 具体创建者2
  41. public class FileLoggerFactory : LoggerFactory
  42. {
  43.     public override ILogger CreateLogger()
  44.     {
  45.         return new FileLogger();
  46.     }
  47. }
  48. // 客户端代码
  49. class Program
  50. {
  51.     static void Main(string[] args)
  52.     {
  53.         LoggerFactory loggerFactory = new ConsoleLoggerFactory();
  54.         loggerFactory.WriteLog("This is a console log.");
  55.         loggerFactory = new FileLoggerFactory();
  56.         loggerFactory.WriteLog("This is a file log.");
  57.     }
  58. }
复制代码
2.1.6.4 特点


2.1.6.5 适用场景


2.2 抽象工厂模式(Abstract Factory Pattern)

2.2.1 定义

抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。它适用于需要创建多个产物族的环境。
2.2.2 结构

抽象工厂模式包罗以下角色:

UML 类图
  1.        +-------------------------+
  2.        |      AbstractFactory     |
  3.        +-------------------------+
  4.        | + CreateProductA()       |
  5.        | + CreateProductB()       |
  6.        +-------------------------+
  7.                 /|\
  8.                  |
  9.        +-------------------------+
  10.        |   ConcreteFactory1       |
  11.        +-------------------------+
  12.        | + CreateProductA()       |
  13.        | + CreateProductB()       |
  14.        +-------------------------+
  15.                  |
  16.        +-------------------------+
  17.        |   ConcreteFactory2       |
  18.        +-------------------------+
  19.        | + CreateProductA()       |
  20.        | + CreateProductB()       |
  21.        +-------------------------+
  22.                 /|\
  23.                  |
  24. +----------------------------+  +----------------------------+
  25. |        AbstractProductA     |  |        AbstractProductB     |
  26. +----------------------------+  +----------------------------+
  27. | + OperationA()              |  | + OperationB()              |
  28. +----------------------------+  +----------------------------+
  29.                 /|\                          /|\
  30.                  |                            |
  31. +----------------------------+  +----------------------------+
  32. |        ProductA1           |  |        ProductB1           |
  33. +----------------------------+  +----------------------------+
  34. | + OperationA()              |  | + OperationB()              |
  35. +----------------------------+  +----------------------------+
  36.                  |
  37. +----------------------------+
  38. |        ProductA2           |
  39. +----------------------------+
  40. | + OperationA()              |
  41. +----------------------------+
复制代码
2.2.3 示例代码

假设我们要创建两种风格的家具:现代风格和维多利亚风格,每种风格包括椅子和沙发。我们可以使用抽象工厂模式来实现。
  1. // 抽象产品A:椅子
  2. public interface IChair
  3. {
  4.     void SitOn();
  5. }
  6. // 抽象产品B:沙发
  7. public interface ISofa
  8. {
  9.     void LieOn();
  10. }
  11. // 具体产品A1:现代椅子
  12. public class ModernChair : IChair
  13. {
  14.     public void SitOn()
  15.     {
  16.         Console.WriteLine("Sitting on a modern chair.");
  17.     }
  18. }
  19. // 具体产品B1:现代沙发
  20. public class ModernSofa : ISofa
  21. {
  22.     public void LieOn()
  23.     {
  24.         Console.WriteLine("Lying on a modern sofa.");
  25.     }
  26. }
  27. // 具体产品A2:维多利亚椅子
  28. public class VictorianChair : IChair
  29. {
  30.     public void SitOn()
  31.     {
  32.         Console.WriteLine("Sitting on a Victorian chair.");
  33.     }
  34. }
  35. // 具体产品B2:维多利亚沙发
  36. public class VictorianSofa : ISofa
  37. {
  38.     public void LieOn()
  39.     {
  40.         Console.WriteLine("Lying on a Victorian sofa.");
  41.     }
  42. }
  43. // 抽象工厂
  44. public interface IFurnitureFactory
  45. {
  46.     IChair CreateChair();
  47.     ISofa CreateSofa();
  48. }
  49. // 具体工厂1:现代家具工厂
  50. public class ModernFurnitureFactory : IFurnitureFactory
  51. {
  52.     public IChair CreateChair()
  53.     {
  54.         return new ModernChair();
  55.     }
  56.     public ISofa CreateSofa()
  57.     {
  58.         return new ModernSofa();
  59.     }
  60. }
  61. // 具体工厂2:维多利亚家具工厂
  62. public class VictorianFurnitureFactory : IFurnitureFactory
  63. {
  64.     public IChair CreateChair()
  65.     {
  66.         return new VictorianChair();
  67.     }
  68.     public ISofa CreateSofa()
  69.     {
  70.         return new VictorianSofa();
  71.     }
  72. }
  73. // 客户端代码
  74. class Program
  75. {
  76.     static void Main(string[] args)
  77.     {
  78.         IFurnitureFactory modernFactory = new ModernFurnitureFactory();
  79.         IChair modernChair = modernFactory.CreateChair();
  80.         ISofa modernSofa = modernFactory.CreateSofa();
  81.         modernChair.SitOn();
  82.         modernSofa.LieOn();
  83.         IFurnitureFactory victorianFactory = new VictorianFurnitureFactory();
  84.         IChair victorianChair = victorianFactory.CreateChair();
  85.         ISofa victorianSofa = victorianFactory.CreateSofa();
  86.         victorianChair.SitOn();
  87.         victorianSofa.LieOn();
  88.     }
  89. }
复制代码
2.2.4 特点


2.2.5 适用场景


2.2.6 比较总结


在实际应用中,工厂方法模式较得当较简单的对象创建场景,而抽象工厂模式则得当更复杂的、多产物族的对象创建需求。
2.3 单例模式(Singleton Pattern)

2.3.1 定义

单例模式确保一个类只有一个实例,并提供一个访问该实例的全局访问点。它可以防止类被多次实例化,并且在某些环境下可以节省内存、确保一致性或控制资源的访问。
2.3.2 结构

单例模式的主要角色包括:

UML 类图
  1. +----------------------+
  2. |      Singleton       |
  3. +----------------------+
  4. | - instance: Singleton|
  5. +----------------------+
  6. | + getInstance():     |
  7. |   Singleton          |
  8. +----------------------+
复制代码
2.3.3 示例代码

单例模式的实现有多种方式,以下是最常见的几种。
懒汉式(Lazy Initialization)
懒汉式实现中,实例在第一次调用 getInstance() 方法时才被创建。这种方式可以耽误实例的创建,节省资源,但在多线程环境下需要举行同步以保证线程安全。
  1. public class Singleton
  2. {
  3.     private static Singleton _instance;
  4.     // 构造函数设置为私有,防止通过new创建实例
  5.     private Singleton() { }
  6.     public static Singleton GetInstance()
  7.     {
  8.         if (_instance == null)
  9.         {
  10.             _instance = new Singleton();
  11.         }
  12.         return _instance;
  13.     }
  14. }
复制代码
线程安全的懒汉式
为了保证线程安全,可以在 getInstance 方法上添加 lock 关键字,但这样大概会低落性能。
  1. public class Singleton
  2. {
  3.     private static Singleton _instance;
  4.     private static readonly object _lock = new object();
  5.     private Singleton() { }
  6.     public static Singleton GetInstance()
  7.     {
  8.         lock (_lock)
  9.         {
  10.             if (_instance == null)
  11.             {
  12.                 _instance = new Singleton();
  13.             }
  14.         }
  15.         return _instance;
  16.     }
  17. }
复制代码
双重查抄锁定(Double-Check Locking)
这种方法在查抄实例是否已经存在时只加一次锁,进步了性能。这是线程安全且高效的实现方式。
  1. public class Singleton
  2. {
  3.     private static Singleton _instance;
  4.     private static readonly object _lock = new object();
  5.     private Singleton() { }
  6.     public static Singleton GetInstance()
  7.     {
  8.         if (_instance == null)
  9.         {
  10.             lock (_lock)
  11.             {
  12.                 if (_instance == null)
  13.                 {
  14.                     _instance = new Singleton();
  15.                 }
  16.             }
  17.         }
  18.         return _instance;
  19.     }
  20. }
复制代码
饿汉式(Eager Initialization)
饿汉式在类加载时就创建实例,因此不存在线程安全题目,但假如实例比较大且未使用时,会浪费资源。
  1. public class Singleton
  2. {
  3.     private static readonly Singleton _instance = new Singleton();
  4.     // 构造函数设置为私有,防止通过new创建实例
  5.     private Singleton() { }
  6.     public static Singleton GetInstance()
  7.     {
  8.         return _instance;
  9.     }
  10. }
复制代码
静态内部类(Static Inner Class)
使用静态内部类的方式可以实现耽误加载和线程安全。静态内部类的实例只会在第一次被引用时初始化,因此可以实现懒加载效果。
  1. public class Singleton
  2. {
  3.     private Singleton() { }
  4.     private static class SingletonHolder
  5.     {
  6.         internal static readonly Singleton _instance = new Singleton();
  7.     }
  8.     public static Singleton GetInstance()
  9.     {
  10.         return SingletonHolder._instance;
  11.     }
  12. }
复制代码
枚举(Enum)
使用枚举来实现单例是最简单和安全的方式,因为枚举实例化是线程安全的,并且只会被实例化一次。这种方式不仅实现了单例,而且还能防止反序列化和反射攻击。
  1. public enum Singleton
  2. {
  3.     Instance;
  4.     public void SomeMethod()
  5.     {
  6.         Console.WriteLine("Singleton method called.");
  7.     }
  8. }
复制代码
2.3.4 特点


2.3.5 适用场景


单例模式在实际开发中非常常见,但在使用时要注意其潜伏的缺陷,特别是在多线程和高并发的环境下,需要选择合适的实现方式以确保线程安全。
2.4 建造者模式(Builder Pattern)

2.4.1 定义

建造者模式将一个复杂对象的构造过程分离出来,使得相同的构造过程可以创建不同的表示。它使用多个简单的对象一步一步构建复杂对象,通过不同的建造者实现不同的构建方式。
2.4.2 结构

建造者模式主要包罗以下角色:

UML 类图
  1. +-------------------+               +-------------------+
  2. |     Director      |               |      Builder      |
  3. +-------------------+               +-------------------+
  4. | - Construct()     |<------------->| + BuildPart()     |
  5. +-------------------+               +-------------------+
  6.         /|\                                   |
  7.          |                                    |
  8.          |                                    |
  9.          |                            +-------------------+
  10.          |                            | ConcreteBuilder   |
  11.          |                            +-------------------+
  12.          |                            | + BuildPart()     |
  13.          |                            | + GetResult()     |
  14.          |                            +-------------------+
  15.          |
  16.          |
  17. +------------------+
  18. |     Product      |
  19. +------------------+
  20. | + AddPart()      |
  21. +------------------+
复制代码
2.4.3 示例代码

下面是一个用建造者模式构建复杂对象的示例。在这个例子中,我们通过建造者模式来创建一种复杂的 House 对象,包罗多个部分如地基、墙壁和屋顶。
产物类
  1. // 产品:House
  2. public class House
  3. {
  4.     private List<string> parts = new List<string>();
  5.     public void AddPart(string part)
  6.     {
  7.         parts.Add(part);
  8.     }
  9.     public void ShowParts()
  10.     {
  11.         Console.WriteLine("House parts:");
  12.         foreach (var part in parts)
  13.         {
  14.             Console.WriteLine(part);
  15.         }
  16.     }
  17. }
复制代码
抽象建造者
  1. // 抽象建造者
  2. public abstract class HouseBuilder
  3. {
  4.     protected House house = new House();
  5.     public abstract void BuildFoundation();
  6.     public abstract void BuildWalls();
  7.     public abstract void BuildRoof();
  8.     public House GetResult()
  9.     {
  10.         return house;
  11.     }
  12. }
复制代码
具体建造者
  1. // 具体建造者1:建造木质房屋
  2. public class WoodenHouseBuilder : HouseBuilder
  3. {
  4.     public override void BuildFoundation()
  5.     {
  6.         house.AddPart("Wooden Foundation");
  7.     }
  8.     public override void BuildWalls()
  9.     {
  10.         house.AddPart("Wooden Walls");
  11.     }
  12.     public override void BuildRoof()
  13.     {
  14.         house.AddPart("Wooden Roof");
  15.     }
  16. }
  17. // 具体建造者2:建造石质房屋
  18. public class StoneHouseBuilder : HouseBuilder
  19. {
  20.     public override void BuildFoundation()
  21.     {
  22.         house.AddPart("Stone Foundation");
  23.     }
  24.     public override void BuildWalls()
  25.     {
  26.         house.AddPart("Stone Walls");
  27.     }
  28.     public override void BuildRoof()
  29.     {
  30.         house.AddPart("Stone Roof");
  31.     }
  32. }
复制代码
指挥者
  1. // 指挥者
  2. public class ConstructionDirector
  3. {
  4.     private HouseBuilder _houseBuilder;
  5.     public void SetBuilder(HouseBuilder builder)
  6.     {
  7.         _houseBuilder = builder;
  8.     }
  9.     public void ConstructHouse()
  10.     {
  11.         _houseBuilder.BuildFoundation();
  12.         _houseBuilder.BuildWalls();
  13.         _houseBuilder.BuildRoof();
  14.     }
  15. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         var director = new ConstructionDirector();
  6.         // 建造木质房屋
  7.         var woodenHouseBuilder = new WoodenHouseBuilder();
  8.         director.SetBuilder(woodenHouseBuilder);
  9.         director.ConstructHouse();
  10.         House woodenHouse = woodenHouseBuilder.GetResult();
  11.         woodenHouse.ShowParts();
  12.         Console.WriteLine();
  13.         // 建造石质房屋
  14.         var stoneHouseBuilder = new StoneHouseBuilder();
  15.         director.SetBuilder(stoneHouseBuilder);
  16.         director.ConstructHouse();
  17.         House stoneHouse = stoneHouseBuilder.GetResult();
  18.         stoneHouse.ShowParts();
  19.     }
  20. }
复制代码
2.4.4 特点


2.4.5 适用场景


2.4.6 与工厂模式对比


建造者模式非常得当在创建复杂对象时使用,尤其是在构建步骤明确且需要控制构建过程的环境下。
2.5 原型模式(Prototype Pattern)

2.5.1 定义

原型模式允许一个对象通过复制自身来创建新的对象。这种模式提供了一种创建对象的快捷方式,尤其适用于创建代价较高的对象。
2.5.2 结构

原型模式的结构包罗以下角色:

UML 类图
  1. +----------------------+                +-------------------------+
  2. |      Prototype       |<---------------|      ConcretePrototype  |
  3. +----------------------+                +-------------------------+
  4. | + Clone(): Prototype |                | + Clone(): Prototype    |
  5. +----------------------+                +-------------------------+
  6.          /|\                                           |
  7.           |                                            |
  8.           |                                            |
  9. +---------------------+                        +---------------------------------+
  10. |      Client         |                        |      AnotherConcretePrototype   |
  11. +---------------------+                        +---------------------------------+
  12. | + Operation()       |                        | + Clone(): Prototype            |
  13. +---------------------+                        +---------------------------------+
复制代码
2.5.3 示例代码

原型模式的焦点在于实现对象的深拷贝或浅拷贝。以下是一个实现原型模式的简单示例,其中我们克隆一个对象来创建新的对象。
原型接口
  1. // 原型接口
  2. public abstract class Prototype
  3. {
  4.     public abstract Prototype Clone();
  5. }
复制代码
具体原型类
  1. // 具体原型类
  2. public class ConcretePrototype : Prototype
  3. {
  4.     public string Name { get; set; }
  5.     public ConcretePrototype(string name)
  6.     {
  7.         Name = name;
  8.     }
  9.     // 实现克隆方法
  10.     public override Prototype Clone()
  11.     {
  12.         return (Prototype)this.MemberwiseClone(); // 浅拷贝
  13.     }
  14. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建一个原型对象
  6.         ConcretePrototype prototype1 = new ConcretePrototype("Prototype 1");
  7.         // 克隆原型对象
  8.         ConcretePrototype clonedPrototype = (ConcretePrototype)prototype1.Clone();
  9.         // 显示克隆对象的属性
  10.         Console.WriteLine("Original Prototype Name: " + prototype1.Name);
  11.         Console.WriteLine("Cloned Prototype Name: " + clonedPrototype.Name);
  12.         // 修改克隆对象的属性
  13.         clonedPrototype.Name = "Cloned Prototype 1";
  14.         Console.WriteLine("\nAfter modification:");
  15.         Console.WriteLine("Original Prototype Name: " + prototype1.Name);
  16.         Console.WriteLine("Cloned Prototype Name: " + clonedPrototype.Name);
  17.     }
  18. }
复制代码
在这个例子中,ConcretePrototype 是具体的原型类,实现了 Clone 方法。Clone 方法使用 MemberwiseClone 来执行浅拷贝,这意味着对象的成员变量会被复制,但对象的引用范例成员变量依然指向同一个内存地址。
浅拷贝与深拷贝:

深拷贝的实现
要实现深拷贝,可以在 Clone 方法中手动复制引用范例的成员变量,或者通过序列化和反序列化来实现。
  1. // 实现深拷贝的具体原型类
  2. [Serializable]
  3. public class DeepConcretePrototype : Prototype
  4. {
  5.     public string Name { get; set; }
  6.     public List<string> Features { get; set; }
  7.     public DeepConcretePrototype(string name, List<string> features)
  8.     {
  9.         Name = name;
  10.         Features = features;
  11.     }
  12.     public override Prototype Clone()
  13.     {
  14.         // 深拷贝:通过序列化和反序列化
  15.         using (MemoryStream stream = new MemoryStream())
  16.         {
  17.             IFormatter formatter = new BinaryFormatter();
  18.             formatter.Serialize(stream, this);
  19.             stream.Seek(0, SeekOrigin.Begin);
  20.             return (Prototype)formatter.Deserialize(stream);
  21.         }
  22.     }
  23. }
复制代码
2.5.4 特点


2.5.5 适用场景


2.5.6 与其他模式对比


原型模式非常得当在对象创建复杂或成本较高的场景下使用,它通过克隆来简化对象的创建过程并进步性能。
2.6 适配器模式(Adapter Pattern)

2.6.1 定义

适配器模式将一个类的接口转换成客户盼望的另一个接口,适配器使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
2.6.2 结构

适配器模式主要包罗以下角色:

UML 类图
  1. +-------------------+        +-------------------+
  2. |      Client       |        |      Target       |
  3. +-------------------+        +-------------------+
  4. | - Request()       |<-------| + Request()       |
  5. +-------------------+        +-------------------+
  6.                                   ^
  7.                                   |
  8.                         +-----------------------+
  9.                         |      Adapter          |
  10.                         +-----------------------+
  11.                         | + Request()           |
  12.                         | - adaptee: Adaptee    |
  13.                         +-----------------------+
  14.                                   |
  15.                                   v
  16.                         +-----------------------+
  17.                         |      Adaptee          |
  18.                         +-----------------------+
  19.                         | + SpecificRequest()   |
  20.                         +-----------------------+
复制代码
2.6.3 示例代码

以下是一个实现适配器模式的简单示例。在这个例子中,Adaptee 类有一个接口 SpecificRequest,它与 Target 接口 Request 不兼容。通过适配器模式,我们可以创建一个适配器类,将 Adaptee 的接口转换为 Target 的接口,使得客户端可以通过 Target 接口与 Adaptee 交互。
目标接口
  1. // 目标接口
  2. public interface ITarget
  3. {
  4.     void Request();
  5. }
复制代码
适配者类
  1. // 需要适配的类
  2. public class Adaptee
  3. {
  4.     public void SpecificRequest()
  5.     {
  6.         Console.WriteLine("Called SpecificRequest()");
  7.     }
  8. }
复制代码
适配器类
  1. // 适配器类
  2. public class Adapter : ITarget
  3. {
  4.     private readonly Adaptee _adaptee;
  5.     public Adapter(Adaptee adaptee)
  6.     {
  7.         _adaptee = adaptee;
  8.     }
  9.     public void Request()
  10.     {
  11.         // 调用适配者的接口,将其转换为目标接口
  12.         _adaptee.SpecificRequest();
  13.     }
  14. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 客户端需要通过 ITarget 接口调用方法
  6.         ITarget target = new Adapter(new Adaptee());
  7.         
  8.         // 客户端通过目标接口与适配器交互
  9.         target.Request();
  10.     }
  11. }
复制代码
2.6.4 特点


2.6.5 适用场景


2.6.6 与其他模式的关系


适配器模式非常得当在项目中需要集成现有体系或类库,而它们的接口又与当前需求不兼容时使用。通过适配器模式,可以在不修改现有代码的条件下实现接口的兼容和扩展。
2.7 桥接模式(Bridge Pattern)

2.7 .1 定义

桥接模式允许在运行时将抽象类与实在现类解耦。它通过引入一个接口来使得抽象类与具体的实现类分开,从而支持两者的独立变化。这样可以避免复杂的多层继承结构。
2.7 .2 结构

桥接模式的结构包罗以下角色:

UML 类图
  1. +-------------------+        +-------------------+
  2. |    Abstraction    |        |   Implementor     |
  3. +-------------------+        +-------------------+
  4. | - implementor     |        | + OperationImpl() |
  5. | + Operation()     |        +-------------------+
  6. +-------------------+                 ^
  7.         |                             |
  8.         |                             |
  9. +-------------------+        +---------------------+
  10. | RefinedAbstraction|        | ConcreteImplementor |
  11. +-------------------+        +---------------------+
  12. | + Operation()     |        | + OperationImpl()   |
  13. +-------------------+        +---------------------+
复制代码
2.7 .3 示例代码

以下是一个实现桥接模式的简单示例。假设我们要创建一个图形绘制程序,其中有不同范例的图形和不同的绘制方式。
实现类接口
  1. // 实现者接口
  2. public interface IColor
  3. {
  4.     void ApplyColor();
  5. }
复制代码
具体实现类
  1. // 具体实现者1:红色
  2. public class RedColor : IColor
  3. {
  4.     public void ApplyColor()
  5.     {
  6.         Console.WriteLine("Applying red color.");
  7.     }
  8. }
  9. // 具体实现者2:绿色
  10. public class GreenColor : IColor
  11. {
  12.     public void ApplyColor()
  13.     {
  14.         Console.WriteLine("Applying green color.");
  15.     }
  16. }
复制代码
抽象类
  1. // 抽象类:形状
  2. public abstract class Shape
  3. {
  4.     protected IColor color;
  5.     protected Shape(IColor color)
  6.     {
  7.         this.color = color;
  8.     }
  9.     public abstract void Draw();
  10. }
复制代码
扩展抽象类
  1. // 细化抽象类1:圆形
  2. public class Circle : Shape
  3. {
  4.     public Circle(IColor color) : base(color)
  5.     {
  6.     }
  7.     public override void Draw()
  8.     {
  9.         Console.Write("Circle is being drawn. ");
  10.         color.ApplyColor();
  11.     }
  12. }
  13. // 细化抽象类2:矩形
  14. public class Rectangle : Shape
  15. {
  16.     public Rectangle(IColor color) : base(color)
  17.     {
  18.     }
  19.     public override void Draw()
  20.     {
  21.         Console.Write("Rectangle is being drawn. ");
  22.         color.ApplyColor();
  23.     }
  24. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建红色和绿色的实现者
  6.         IColor red = new RedColor();
  7.         IColor green = new GreenColor();
  8.         // 创建带有不同颜色的形状
  9.         Shape redCircle = new Circle(red);
  10.         Shape greenRectangle = new Rectangle(green);
  11.         // 画形状
  12.         redCircle.Draw();  // 输出: Circle is being drawn. Applying red color.
  13.         greenRectangle.Draw();  // 输出: Rectangle is being drawn. Applying green color.
  14.     }
  15. }
复制代码
在这个例子中:

2.7 .4 特点


2.7 .5 适用场景


2.7 .6 与其他模式的关系


桥接模式通过将抽象与实现分离,使得体系的扩展更加灵活,适用于需要同时支持多种变化的场景。
2.8 组合模式(Composite Pattern)

2.8.1 定义

组合模式通过定义树形结构来构成对象,使得客户端对单个对象和对象聚集的处理方式一致。这个模式让你可以使用相同的接口来操作单一对象和对象聚集,简化了代码和操作逻辑。
2.8.2 结构

组合模式的结构包罗以下角色:

UML 类图
  1. +---------------------+
  2. |     Component       |
  3. +---------------------+
  4. | + Operation()       |
  5. +---------------------+
  6. | + Add(Component)    |
  7. | + Remove(Component) |
  8. | + GetChild(int)     |
  9. +---------------------+
  10.           ^
  11.           |
  12. +---------------------+       +---------------------+
  13. |      Leaf           |       |     Composite       |
  14. +---------------------+       +---------------------+
  15. | + Operation()       |       | + Operation()       |
  16. +---------------------+       +---------------------+
  17.                               | + Add(Component)    |
  18.                               | + Remove(Component) |
  19.                               | + GetChild(int)     |
  20.                               +---------------------+
复制代码
2.8.3 示例代码

以下是一个实现组合模式的简单示例。在这个示例中,我们有一个文件体系,其中 File 是叶子节点,Directory 是复合节点(目次),它可以包罗多个文件或目次。
组件接口
  1. // 组件接口
  2. public abstract class FileSystemComponent
  3. {
  4.     public abstract void Display(int depth);
  5.     // 组合节点的方法
  6.     public virtual void Add(FileSystemComponent component) { }
  7.     public virtual void Remove(FileSystemComponent component) { }
  8.     public virtual FileSystemComponent GetChild(int index) { return null; }
  9. }
复制代码
叶子节点类
  1. // 叶子节点类:文件
  2. public class File : FileSystemComponent
  3. {
  4.     private string _name;
  5.     public File(string name)
  6.     {
  7.         _name = name;
  8.     }
  9.     public override void Display(int depth)
  10.     {
  11.         Console.WriteLine(new string('-', depth) + _name);
  12.     }
  13. }
复制代码
复合节点类
  1. // 复合节点类:目录
  2. public class Directory : FileSystemComponent
  3. {
  4.     private List<FileSystemComponent> _children = new List<FileSystemComponent>();
  5.     private string _name;
  6.     public Directory(string name)
  7.     {
  8.         _name = name;
  9.     }
  10.     public override void Add(FileSystemComponent component)
  11.     {
  12.         _children.Add(component);
  13.     }
  14.     public override void Remove(FileSystemComponent component)
  15.     {
  16.         _children.Remove(component);
  17.     }
  18.     public override FileSystemComponent GetChild(int index)
  19.     {
  20.         return _children[index];
  21.     }
  22.     public override void Display(int depth)
  23.     {
  24.         Console.WriteLine(new string('-', depth) + _name);
  25.         foreach (var child in _children)
  26.         {
  27.             child.Display(depth + 2);
  28.         }
  29.     }
  30. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建文件和目录
  6.         FileSystemComponent file1 = new File("File 1");
  7.         FileSystemComponent file2 = new File("File 2");
  8.         FileSystemComponent file3 = new File("File 3");
  9.         Directory directory1 = new Directory("Directory 1");
  10.         Directory directory2 = new Directory("Directory 2");
  11.         // 构建目录树
  12.         directory1.Add(file1);
  13.         directory1.Add(file2);
  14.         directory2.Add(file3);
  15.         directory2.Add(directory1);
  16.         // 显示目录树
  17.         directory2.Display(1);
  18.     }
  19. }
复制代码
在这个示例中:

2.8.4 特点


2.8.5 适用场景


2.8.6 与其他模式对比


组合模式非常得当用来构建复杂的树形结构,通过将对象和对象聚集统一成一个接口,它能够简化对复杂结构的操作,并进步体系的灵活性和可扩展性。
2.9 装饰器模式(Decorator Pattern)

2.9.1 定义

装饰器模式通过创建一个装饰器类,它实现了与被装饰对象相同的接口,从而可以在运行时动态地添加新功能。这种模式提供了一种灵活的替代方案来扩展对象的功能,避免了使用子类来扩展功能的需要。
2.9.2 结构

装饰器模式的结构包罗以下角色:

UML 类图
  1. +-------------------+
  2. |     Component     |
  3. +-------------------+
  4. | + Operation()     |
  5. +-------------------+
  6.         ^
  7.         |
  8. +-------------------+          +---------------------------+
  9. | ConcreteComponent | <------- |    Decorator              |
  10. +-------------------+          +---------------------------+
  11. | + Operation()     |          | - component: Component    |
  12. +-------------------+          | + Operation()             |
  13.                                +---------------------------+
  14.                                           ^
  15.                                           |
  16.                                +------------------------+
  17.                                |  ConcreteDecorator     |
  18.                                +------------------------+
  19.                                | + Operation()          |
  20.                                | + AdditionalBehavior() |
  21.                                +------------------------+
复制代码
2.9.3 示例代码

以下是一个实现装饰器模式的简单示例。在这个示例中,我们有一个饮料的体系,可以为饮料添加不同的配料(装饰)。
组件接口
  1. // 组件接口
  2. public abstract class Beverage
  3. {
  4.     public abstract string GetDescription();
  5.     public abstract double Cost();
  6. }
复制代码
具体组件类
  1. // 具体组件:咖啡
  2. public class Coffee : Beverage
  3. {
  4.     public override string GetDescription()
  5.     {
  6.         return "Coffee";
  7.     }
  8.     public override double Cost()
  9.     {
  10.         return 2.00; // 基本咖啡的价格
  11.     }
  12. }
复制代码
装饰器类
  1. // 装饰器类
  2. public abstract class CondimentDecorator : Beverage
  3. {
  4.     protected Beverage _beverage;
  5.     public CondimentDecorator(Beverage beverage)
  6.     {
  7.         _beverage = beverage;
  8.     }
  9. }
复制代码
具体装饰器类
  1. // 具体装饰器:牛奶
  2. public class MilkDecorator : CondimentDecorator
  3. {
  4.     public MilkDecorator(Beverage beverage) : base(beverage)
  5.     {
  6.     }
  7.     public override string GetDescription()
  8.     {
  9.         return _beverage.GetDescription() + ", Milk";
  10.     }
  11.     public override double Cost()
  12.     {
  13.         return _beverage.Cost() + 0.50; // 添加牛奶的价格
  14.     }
  15. }
  16. // 具体装饰器:巧克力
  17. public class ChocolateDecorator : CondimentDecorator
  18. {
  19.     public ChocolateDecorator(Beverage beverage) : base(beverage)
  20.     {
  21.     }
  22.     public override string GetDescription()
  23.     {
  24.         return _beverage.GetDescription() + ", Chocolate";
  25.     }
  26.     public override double Cost()
  27.     {
  28.         return _beverage.Cost() + 0.70; // 添加巧克力的价格
  29.     }
  30. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建基本的咖啡
  6.         Beverage beverage = new Coffee();
  7.         // 添加配料
  8.         beverage = new MilkDecorator(beverage);
  9.         beverage = new ChocolateDecorator(beverage);
  10.         // 显示描述和总费用
  11.         Console.WriteLine($"{beverage.GetDescription()} costs {beverage.Cost():C}");
  12.     }
  13. }
复制代码
在这个示例中:

2.9.4 特点


2.9.5 适用场景


2.9.6 与其他模式对比


装饰器模式提供了一种灵活的方式来扩展对象的功能,使得开发者可以在不影响已有代码的环境下,轻松地添加新的行为或属性。
2.10 外观模式(Facade Pattern)

2.10.1 定义

外观模式通过为复杂的子体系提供一个简化的接口,使得客户端可以通过这个接口访问子体系的功能,而不需要直接与子体系的多个组件举行交互。外观模式可以隐藏子体系的复杂性,并且使得子体系与客户端的耦合度低落。
2.10.2 结构

外观模式的结构包罗以下角色:

UML 类图
  1.                             +-------------------+
  2.                             |      Client       |
  3.                             +-------------------+
  4.                                      ^
  5.                                      |
  6. +-------------------+       +-------------------+       +-------------------+
  7. |    SubsystemA     | ----> |      Facade       | <---- |    SubsystemC     |
  8. +-------------------+       +-------------------+       +-------------------+
  9.                                      ^                           ^
  10.                                      |                           |
  11.                             +-------------------+       +-------------------+
  12.                             |    SubsystemB     |       |    SubsystemD     |
  13.                             +-------------------+       +-------------------+
复制代码
2.10.3 示例代码

以下是一个实现外观模式的简单示例。在这个示例中,我们构建了一个家庭影院体系,客户端通过外观类 HomeTheaterFacade 来控制各个子体系,如电视、音响、灯光等。
子体系类
  1. // 子系统类:电视
  2. public class Television
  3. {
  4.     public void On()
  5.     {
  6.         Console.WriteLine("Television is on.");
  7.     }
  8.     public void Off()
  9.     {
  10.         Console.WriteLine("Television is off.");
  11.     }
  12. }
  13. // 子系统类:音响
  14. public class SoundSystem
  15. {
  16.     public void On()
  17.     {
  18.         Console.WriteLine("Sound system is on.");
  19.     }
  20.     public void Off()
  21.     {
  22.         Console.WriteLine("Sound system is off.");
  23.     }
  24.     public void SetVolume(int volume)
  25.     {
  26.         Console.WriteLine($"Sound system volume set to {volume}.");
  27.     }
  28. }
  29. // 子系统类:灯光
  30. public class Lights
  31. {
  32.     public void Dim(int level)
  33.     {
  34.         Console.WriteLine($"Lights dimmed to {level}%.");
  35.     }
  36.     public void On()
  37.     {
  38.         Console.WriteLine("Lights are on.");
  39.     }
  40. }
复制代码
外观类
  1. // 外观类:家庭影院
  2. public class HomeTheaterFacade
  3. {
  4.     private readonly Television _television;
  5.     private readonly SoundSystem _soundSystem;
  6.     private readonly Lights _lights;
  7.     public HomeTheaterFacade(Television television, SoundSystem soundSystem, Lights lights)
  8.     {
  9.         _television = television;
  10.         _soundSystem = soundSystem;
  11.         _lights = lights;
  12.     }
  13.     public void WatchMovie()
  14.     {
  15.         Console.WriteLine("Get ready to watch a movie...");
  16.         _lights.Dim(30);
  17.         _television.On();
  18.         _soundSystem.On();
  19.         _soundSystem.SetVolume(5);
  20.     }
  21.     public void EndMovie()
  22.     {
  23.         Console.WriteLine("Shutting movie theater down...");
  24.         _television.Off();
  25.         _soundSystem.Off();
  26.         _lights.On();
  27.     }
  28. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建子系统对象
  6.         Television television = new Television();
  7.         SoundSystem soundSystem = new SoundSystem();
  8.         Lights lights = new Lights();
  9.         // 创建外观对象
  10.         HomeTheaterFacade homeTheater = new HomeTheaterFacade(television, soundSystem, lights);
  11.         // 使用外观模式控制子系统
  12.         homeTheater.WatchMovie();
  13.         Console.WriteLine("\nMovie is running...\n");
  14.         homeTheater.EndMovie();
  15.     }
  16. }
复制代码
在这个例子中:

2.10.4 特点


2.10.5 适用场景


2.10.6 与其他模式的关系


外观模式通过提供一个统一和简化的接口来隐藏体系的复杂性,使得客户端能够更轻松地使用体系,同时保持体系内部结构的灵活性和可扩展性。
2.11 享元模式(Flyweight Pattern)

2.11.1 定义

享元模式的焦点头脑是将对象的状态分为内部状态(可以共享的部分)和外部状态(不能共享的部分)。通过共享相同的内部状态,减少内存的重复占用,从而实现体系的资源优化。
2.11.2 结构

享元模式的结构包罗以下角色:

UML 类图
  1. +-------------------+
  2. |   IFlyweight      |
  3. +-------------------+
  4. | + Operation()     |
  5. +-------------------+
  6.         ^
  7.         |
  8. +-----------------------+
  9. |   ConcreteFlyweight   |
  10. +-----------------------+
  11. | - property1           |       // 共享的内部状态
  12. | - property2           |       // 共享的内部状态
  13. | + Operation()         |
  14. +-----------------------+
  15. +-------------------+
  16. | FlyweightFactory  |
  17. +-------------------+
  18. | - flyweights      |
  19. | + Operation()     |
  20. +-------------------+
  21. +---------------------------+
  22. | UnsharedConcreteFlyweight |
  23. +---------------------------+
  24. | - property1               |       // 不共享的外部状态
  25. | - property2               |       // 不共享的外部状态
  26. | - flyweight               |       // 组合享元
  27. | + Operation()             |
  28. +---------------------------+
复制代码
2.11.3 示例代码

2.11.3.1 文字处理器

以下是一个实现享元模式的简单示例。在这个示例中,我们模仿了一个文字处理器,其中的字符对象可以被共享,以减少内存的占用。
享元接口
  1. // 享元接口
  2. public interface ICharacter
  3. {
  4.     void Display(int fontSize);
  5. }
复制代码
具体享元类
  1. // 具体享元类:字符
  2. public class Character : ICharacter
  3. {
  4.     private readonly char _symbol;  // 内部状态(共享部分)
  5.     public Character(char symbol)
  6.     {
  7.         _symbol = symbol;
  8.     }
  9.     public void Display(int fontSize)
  10.     {
  11.         Console.WriteLine($"Character: {_symbol}, Font size: {fontSize}");
  12.     }
  13. }
复制代码
享元工厂类
  1. // 享元工厂类
  2. public class CharacterFactory
  3. {
  4.     private readonly Dictionary<char, ICharacter> _characters = new Dictionary<char, ICharacter>();
  5.     public ICharacter GetCharacter(char symbol)
  6.     {
  7.         if (!_characters.ContainsKey(symbol))
  8.         {
  9.             _characters[symbol] = new Character(symbol);  // 创建新的享元对象
  10.         }
  11.         return _characters[symbol];  // 返回共享的享元对象
  12.     }
  13. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         CharacterFactory factory = new CharacterFactory();
  6.         // 获取并显示字符对象
  7.         ICharacter a = factory.GetCharacter('A');
  8.         a.Display(12);
  9.         ICharacter b = factory.GetCharacter('B');
  10.         b.Display(14);
  11.         ICharacter a2 = factory.GetCharacter('A');
  12.         a2.Display(18);
  13.         // 检查两个 'A' 字符是否为同一个实例
  14.         Console.WriteLine($"Is 'A' and 'A2' the same instance? {ReferenceEquals(a, a2)}");
  15.     }
  16. }
复制代码
在这个例子中:

2.11.3.2 棋子与棋盘的实现示例

享元接口
  1. // 享元接口:棋子
  2. public interface IChessPiece
  3. {
  4.     void Display(int x, int y);
  5. }
复制代码
具体享元类
  1. // 具体享元类:具体的棋子,如"黑车"或"白马"
  2. public class ChessPiece : IChessPiece
  3. {
  4.     private readonly string _color;  // 内部状态(共享部分)
  5.     private readonly string _type;   // 内部状态(共享部分)
  6.     public ChessPiece(string color, string type)
  7.     {
  8.         _color = color;
  9.         _type = type;
  10.     }
  11.     public void Display(int x, int y)
  12.     {
  13.         Console.WriteLine($"Chess Piece: {_color} {_type}, Position: ({x}, {y})");
  14.     }
  15. }
复制代码
享元工厂类
  1. // 享元工厂类:负责管理棋子对象
  2. public class ChessPieceFactory
  3. {
  4.     private readonly Dictionary<string, IChessPiece> _pieces = new Dictionary<string, IChessPiece>();
  5.     public IChessPiece GetChessPiece(string color, string type)
  6.     {
  7.         string key = color + "_" + type;
  8.         if (!_pieces.ContainsKey(key))
  9.         {
  10.             _pieces[key] = new ChessPiece(color, type);
  11.         }
  12.         return _pieces[key];
  13.     }
  14. }
复制代码
非共享具体享元类
  1. // 非共享具体享元类:棋盘上的棋子
  2. public class ChessBoardPosition
  3. {
  4.     private readonly int _x;  // 外部状态
  5.     private readonly int _y;  // 外部状态
  6.     private readonly IChessPiece _chessPiece;  // 共享享元
  7.     public ChessBoardPosition(int x, int y, IChessPiece chessPiece)
  8.     {
  9.         _x = x;
  10.         _y = y;
  11.         _chessPiece = chessPiece;
  12.     }
  13.     public void Display()
  14.     {
  15.         _chessPiece.Display(_x, _y);
  16.     }
  17. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         ChessPieceFactory factory = new ChessPieceFactory();
  6.         // 获取棋子,并在棋盘上设置位置
  7.         ChessBoardPosition position1 = new ChessBoardPosition(1, 1, factory.GetChessPiece("Black", "Rook"));
  8.         ChessBoardPosition position2 = new ChessBoardPosition(1, 2, factory.GetChessPiece("Black", "Knight"));
  9.         ChessBoardPosition position3 = new ChessBoardPosition(1, 3, factory.GetChessPiece("Black", "Bishop"));
  10.         ChessBoardPosition position4 = new ChessBoardPosition(1, 1, factory.GetChessPiece("White", "Pawn"));
  11.         // 显示棋盘上的棋子
  12.         position1.Display();
  13.         position2.Display();
  14.         position3.Display();
  15.         position4.Display();
  16.     }
  17. }
复制代码
在这个例子中:

2.11.4 特点


2.11.5 适用场景


2.11.6 与其他模式的关系


享元模式通过共享对象的内部状态,有效地减少了内存的占用,是优化体系性能的一种有效手段,特别是在需要大量相似对象的环境下。
2.12 代理模式(Proxy Pattern)

2.12.1 定义

代理模式通过创建一个代理对象来控制对另一个对象的访问。代理对象具有与原对象相同的接口,客户端可以通过代理对象访问实际的服务对象。代理对象可以在不影响客户端的环境下,对请求举行预处理或后处理。
2.12.2 结构

代理模式的结构包罗以下角色:

UML 类图
  1. +-----------------+
  2. |   Subject       | <--------- 抽象主题
  3. +-----------------+                 |
  4. | + Request()     |                 |
  5. +-----------------+                 |
  6.         ^                           |
  7.         |                           |
  8. +-----------------+         +-----------------+
  9. |   Proxy         |         |  RealSubject    |
  10. +-----------------+         +-----------------+
  11. | - realSubject:  | ------- | + Request()     |
  12. |   RealSubject   |         +-----------------+
  13. | + Request()     |
  14. +-----------------+
复制代码
2.12.3 示例代码

假设我们有一个需要访问的图像文件对象。图像文件大概很大,所以我们盼望在图像真正需要体现时才加载它。在这种环境下,我们可以使用代理模式。
抽象主题接口
  1. // 抽象主题
  2. public interface IImage
  3. {
  4.     void Display();
  5. }
复制代码
真实主题类
  1. // 真实主题类:真实的图像文件
  2. public class RealImage : IImage
  3. {
  4.     private readonly string _filename;
  5.     public RealImage(string filename)
  6.     {
  7.         _filename = filename;
  8.         LoadImageFromDisk();  // 模拟加载图像文件
  9.     }
  10.     private void LoadImageFromDisk()
  11.     {
  12.         Console.WriteLine($"Loading image from disk: {_filename}");
  13.     }
  14.     public void Display()
  15.     {
  16.         Console.WriteLine($"Displaying image: {_filename}");
  17.     }
  18. }
复制代码
代理类
  1. // 代理类:代理图像
  2. public class ProxyImage : IImage
  3. {
  4.     private RealImage _realImage;
  5.     private readonly string _filename;
  6.     public ProxyImage(string filename)
  7.     {
  8.         _filename = filename;
  9.     }
  10.     public void Display()
  11.     {
  12.         if (_realImage == null)
  13.         {
  14.             _realImage = new RealImage(_filename);  // 延迟加载
  15.         }
  16.         _realImage.Display();
  17.     }
  18. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         IImage image = new ProxyImage("test_image.jpg");
  6.         // 图像第一次显示时,代理对象会加载真实图像
  7.         image.Display();
  8.         // 图像再次显示时,不需要再次加载
  9.         image.Display();
  10.     }
  11. }
复制代码
在这个例子中:

运行效果
运行上述代码,你会看到以下输出:
  1. Loading image from disk: test_image.jpg
  2. Displaying image: test_image.jpg
  3. Displaying image: test_image.jpg
复制代码
在这个例子中,图像在第一次调用 Display() 时才会加载,之后的调用直接体现图像,无需再次加载。这就是代理模式的耽误加载(Lazy Loading)应用。
2.12.4 特点


2.12.5 适用场景


2.12.6 与其他模式的关系


代理模式在计划复杂体系时提供了非常灵活的对象管理方式,通过合理使用代理,可以有效地提升体系的性能和安全性。
2.13 责任链模式(Chain of Responsibility Pattern)

2.13.1 定义

责任链模式的焦点头脑是将请求沿着处理者链通报,直到其中一个处理者处理这个请求。这种模式的一个重要特性是:请求的发送者并不知道哪个对象会最终处理请求,体系中的处理者对象也无需知道其他处理者的结构,处理者之间的解耦进步了体系的灵活性。
2.13.2 结构

责任链模式包罗以下角色:

UML 类图
  1. +-----------------------------------+
  2. |    Handler                        |  <----- 抽象处理者
  3. +-----------------------------------+
  4. | - next: Handler                   |  <----- 链中下一个处理者的引用
  5. | + SetNext(handler: Handler)       |
  6. | + HandleRequest(request: Request) |
  7. +-----------------------------------+
  8.         ^
  9.         |
  10. +-----------------------------------+    +-----------------------------------+
  11. |  ConcreteHandler1                 |    |  ConcreteHandler2                 |
  12. +-----------------------------------+    +-----------------------------------+
  13. | + HandleRequest(request: Request) |    | + HandleRequest(request: Request) |
  14. +-----------------------------------+    +-----------------------------------+
复制代码
2.13.3 示例代码

假设我们有一个支持多级审批的体系,每个级别的审批员处理不同级别的请求。请求可以从一个审批员通报到下一个审批员,直到某个审批员处理了请求或者请求被拒绝。
抽象处理者
  1. // 抽象处理者
  2. public abstract class Approver
  3. {
  4.     protected Approver _nextApprover;
  5.     public void SetNext(Approver nextApprover)
  6.     {
  7.         _nextApprover = nextApprover;
  8.     }
  9.     public abstract void ProcessRequest(PurchaseRequest request);
  10. }
复制代码
具体处理者
  1. // 具体处理者1:经理
  2. public class Manager : Approver
  3. {
  4.     public override void ProcessRequest(PurchaseRequest request)
  5.     {
  6.         if (request.Amount < 10000)
  7.         {
  8.             Console.WriteLine($"{this.GetType().Name} approved request# {request.Number}");
  9.         }
  10.         else if (_nextApprover != null)
  11.         {
  12.             _nextApprover.ProcessRequest(request);
  13.         }
  14.     }
  15. }
  16. // 具体处理者2:总监
  17. public class Director : Approver
  18. {
  19.     public override void ProcessRequest(PurchaseRequest request)
  20.     {
  21.         if (request.Amount < 25000)
  22.         {
  23.             Console.WriteLine($"{this.GetType().Name} approved request# {request.Number}");
  24.         }
  25.         else if (_nextApprover != null)
  26.         {
  27.             _nextApprover.ProcessRequest(request);
  28.         }
  29.     }
  30. }
  31. // 具体处理者3:副总裁
  32. public class VicePresident : Approver
  33. {
  34.     public override void ProcessRequest(PurchaseRequest request)
  35.     {
  36.         if (request.Amount < 50000)
  37.         {
  38.             Console.WriteLine($"{this.GetType().Name} approved request# {request.Number}");
  39.         }
  40.         else if (_nextApprover != null)
  41.         {
  42.             _nextApprover.ProcessRequest(request);
  43.         }
  44.     }
  45. }
  46. // 具体处理者4:总裁
  47. public class President : Approver
  48. {
  49.     public override void ProcessRequest(PurchaseRequest request)
  50.     {
  51.         if (request.Amount < 100000)
  52.         {
  53.             Console.WriteLine($"{this.GetType().Name} approved request# {request.Number}");
  54.         }
  55.         else
  56.         {
  57.             Console.WriteLine($"Request# {request.Number} requires an executive meeting!");
  58.         }
  59.     }
  60. }
复制代码
请求类
  1. // 请求类:采购请求
  2. public class PurchaseRequest
  3. {
  4.     public int Number { get; }
  5.     public double Amount { get; }
  6.     public string Purpose { get; }
  7.     public PurchaseRequest(int number, double amount, string purpose)
  8.     {
  9.         Number = number;
  10.         Amount = amount;
  11.         Purpose = purpose;
  12.     }
  13. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建处理者对象
  6.         Approver manager = new Manager();
  7.         Approver director = new Director();
  8.         Approver vp = new VicePresident();
  9.         Approver president = new President();
  10.         // 设置责任链
  11.         manager.SetNext(director);
  12.         director.SetNext(vp);
  13.         vp.SetNext(president);
  14.         // 创建多个采购请求
  15.         PurchaseRequest request1 = new PurchaseRequest(1, 5000, "Buy supplies");
  16.         PurchaseRequest request2 = new PurchaseRequest(2, 20000, "Buy projectors");
  17.         PurchaseRequest request3 = new PurchaseRequest(3, 35000, "Buy laptops");
  18.         PurchaseRequest request4 = new PurchaseRequest(4, 90000, "Buy servers");
  19.         // 处理请求
  20.         manager.ProcessRequest(request1);
  21.         manager.ProcessRequest(request2);
  22.         manager.ProcessRequest(request3);
  23.         manager.ProcessRequest(request4);
  24.     }
  25. }
复制代码
运行效果
  1. Manager approved request# 1
  2. Director approved request# 2
  3. VicePresident approved request# 3
  4. President approved request# 4
复制代码
在这个例子中,Manager、Director、VicePresident 和 President 这四个处理者构成了一个责任链。每个处理者都查抄请求的金额,并决定是否可以处理请求,假如不能处理则将请求通报给下一个处理者。
2.13.5 特点


2.13.6 适用场景


2.13.7 总结

责任链模式通过将处理者对象串联成一条链,使请求能够沿着链通报,直到被某个处理者处理。这种模式的灵活性使其适用于多种场景,尤其是那些需要动态指定请求处理者或处理者职责大概发生变化的场合。
2.14 下令模式(Command Pattern)

2.14.1 定义

下令模式的焦点头脑是将“请求”封装为对象,并将请求的执行和请求的具体操作细节解耦。这样可以在不同的时间点、不同的环境下执行请求,还可以通过下令对象的统一接口来记录日记、撤销操作等。
2.14.2 结构

下令模式包罗以下角色:

UML 类图
  1. +-------------------+
  2. |     Command       |  <----- 命令接口
  3. +-------------------+
  4. | + Execute()       |
  5. +-------------------+
  6.         ^
  7.         |
  8. +-----------------------+            +----------------------+
  9. | ConcreteCommand1      |            | ConcreteCommand2     |
  10. +-----------------------+            +----------------------+
  11. | - receiver: Receiver  |            | - receiver: Receiver |
  12. | + Execute()           |            | + Execute()          |
  13. +-----------------------+            +----------------------+
  14. +-------------------+
  15. |     Receiver      |  <----- 接收者
  16. +-------------------+
  17. | + Action()        |
  18. +-------------------+
  19. +-----------------------------+
  20. |     Invoker                 |  <----- 调用者
  21. +-----------------------------+
  22. | - command: Command          |
  23. | + SetCommand(cmd: Command)  |
  24. | + ExecuteCommand()          |
  25. +-----------------------------+
复制代码
2.14.3 示例代码

假设我们要实现一个简单的家电控制体系,可以用下令模式来计划将家电的操作(如开灯、关灯等)封装为下令对象。
下令接口
  1. // 命令接口
  2. public interface ICommand
  3. {
  4.     void Execute();
  5.     void Undo();
  6. }
复制代码
接收者
  1. // 接收者:灯
  2. public class Light
  3. {
  4.     public void TurnOn()
  5.     {
  6.         Console.WriteLine("The light is on");
  7.     }
  8.     public void TurnOff()
  9.     {
  10.         Console.WriteLine("The light is off");
  11.     }
  12. }
复制代码
具体下令类
  1. // 具体命令类:打开灯
  2. public class LightOnCommand : ICommand
  3. {
  4.     private readonly Light _light;
  5.     public LightOnCommand(Light light)
  6.     {
  7.         _light = light;
  8.     }
  9.     public void Execute()
  10.     {
  11.         _light.TurnOn();
  12.     }
  13.     public void Undo()
  14.     {
  15.         _light.TurnOff(); // 撤销打开灯,实际上是关闭灯
  16.     }
  17. }
  18. // 具体命令类:关闭灯
  19. public class LightOffCommand : ICommand
  20. {
  21.     private readonly Light _light;
  22.     public LightOffCommand(Light light)
  23.     {
  24.         _light = light;
  25.     }
  26.     public void Execute()
  27.     {
  28.         _light.TurnOff();
  29.     }
  30.     public void Undo()
  31.     {
  32.         _light.TurnOn(); // 撤销关闭灯,实际上是打开灯
  33.     }
  34. }
复制代码
调用者
  1. public class RemoteControl
  2. {
  3.     private ICommand _command;
  4.     private readonly Stack<ICommand> _history = new Stack<ICommand>();
  5.     private readonly Stack<ICommand> _redoStack = new Stack<ICommand>();
  6.     public void SetCommand(ICommand command)
  7.     {
  8.         _command = command;
  9.     }
  10.     public void PressButton()
  11.     {
  12.         _command.Execute();
  13.         _history.Push(_command); // 保存执行的命令
  14.         _redoStack.Clear();      // 清空恢复栈,因为有新操作了
  15.     }
  16.     public void PressUndo()
  17.     {
  18.         if (_history.Count > 0)
  19.         {
  20.             ICommand lastCommand = _history.Pop();
  21.             lastCommand.Undo();
  22.             _redoStack.Push(lastCommand); // 保存到恢复栈
  23.         }
  24.     }
  25.     public void PressRedo()
  26.     {
  27.         if (_redoStack.Count > 0)
  28.         {
  29.             ICommand lastUndoneCommand = _redoStack.Pop();
  30.             lastUndoneCommand.Execute();
  31.             _history.Push(lastUndoneCommand); // 重新保存到历史栈
  32.         }
  33.     }
  34. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建接收者
  6.         Light livingRoomLight = new Light();
  7.         // 创建命令对象
  8.         ICommand lightOn = new LightOnCommand(livingRoomLight);
  9.         ICommand lightOff = new LightOffCommand(livingRoomLight);
  10.         // 创建调用者并设置命令
  11.         RemoteControl remote = new RemoteControl();
  12.         // 打开灯
  13.         remote.SetCommand(lightOn);
  14.         remote.PressButton();
  15.         // 关闭灯
  16.         remote.SetCommand(lightOff);
  17.         remote.PressButton();
  18.         // 撤销关闭灯操作(即再次打开灯)
  19.         remote.PressUndo();
  20.         // 撤销打开灯操作(即再次关闭灯)
  21.         remote.PressUndo();
  22.         // 恢复关闭灯操作(即再次打开灯)
  23.         remote.PressRedo();
  24.     }
  25. }
复制代码
运行效果
  1. The light is on
  2. The light is off
复制代码
在这个例子中,LightOnCommand 和 LightOffCommand 这两个具体下令类封装了开灯和关灯的操作。RemoteControl 是调用者,通过调用 SetCommand 方法将具体下令对象通报给它,并通过 PressButton 方法执行下令。
2.14.4 特点


2.14.5 适用场景


2.14.6 总结

下令模式通过将操作封装为独立的下令对象,实现了请求发送者与接收者的解耦。它为体系增加了灵活性,尤其是在支持撤销、恢复、宏下令和请求排队等功能时非常有效。然而,下令模式的使用也大概导致类的数量增加,体系的复杂性增加,因此在计划时需要衡量使用。
2.15 解释器模式(Interpreter Pattern)

2.15.1 定义

解释器模式通过定义一种语言的语法规则,使用这些规则剖析和执行语言中的语句。这种模式通常用于那些具有简单语法和小型下令集的范畴特定语言(DSL)中。
2.15.2 结构

解释器模式包罗以下角色:

UML 类图
  1. +---------------------------------------+
  2. |  AbstractExpression                   |  <----- 抽象表达式
  3. +---------------------------------------+
  4. | + Interpret(context: Context): void   |
  5. +---------------------------------------+
  6.         ^
  7.         |
  8. +---------------------------------------+    +---------------------------------------+
  9. | TerminalExpression                    |    | NonTerminalExpression                 |
  10. +---------------------------------------+    +---------------------------------------+
  11. | + Interpret(context: Context): void   |    | + Interpret(context: Context): void   |
  12. +---------------------------------------+    +---------------------------------------+
  13. +-------------------+
  14. |     Context       |  <----- 上下文
  15. +-------------------+
  16. | + GetInfo(): ...  |
  17. +-------------------+
复制代码
2.15.3 示例代码

假设我们要实现一个简单的数学表达式解释器,可以剖析和盘算简单的加法和减法运算表达式。
抽象表达式
  1. // 抽象表达式
  2. public interface IExpression
  3. {
  4.     int Interpret();
  5. }
复制代码
闭幕符表达式
  1. // 终结符表达式:数字
  2. public class NumberExpression : IExpression
  3. {
  4.     private readonly int _number;
  5.     public NumberExpression(int number)
  6.     {
  7.         _number = number;
  8.     }
  9.     public int Interpret()
  10.     {
  11.         return _number;
  12.     }
  13. }
复制代码
非闭幕符表达式
  1. // 非终结符表达式:加法
  2. public class AddExpression : IExpression
  3. {
  4.     private readonly IExpression _leftExpression;
  5.     private readonly IExpression _rightExpression;
  6.     public AddExpression(IExpression leftExpression, IExpression rightExpression)
  7.     {
  8.         _leftExpression = leftExpression;
  9.         _rightExpression = rightExpression;
  10.     }
  11.     public int Interpret()
  12.     {
  13.         return _leftExpression.Interpret() + _rightExpression.Interpret();
  14.     }
  15. }
  16. // 非终结符表达式:减法
  17. public class SubtractExpression : IExpression
  18. {
  19.     private readonly IExpression _leftExpression;
  20.     private readonly IExpression _rightExpression;
  21.     public SubtractExpression(IExpression leftExpression, IExpression rightExpression)
  22.     {
  23.         _leftExpression = leftExpression;
  24.         _rightExpression = rightExpression;
  25.     }
  26.     public int Interpret()
  27.     {
  28.         return _leftExpression.Interpret() - _rightExpression.Interpret();
  29.     }
  30. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 构造表达式:10 + 5 - 2
  6.         IExpression expression = new SubtractExpression(
  7.             new AddExpression(new NumberExpression(10), new NumberExpression(5)),
  8.             new NumberExpression(2)
  9.         );
  10.         // 解释并计算结果
  11.         int result = expression.Interpret();
  12.         Console.WriteLine($"Result: {result}");
  13.     }
  14. }
复制代码
运行效果
  1. Result: 13
复制代码
在这个例子中,表达式 10 + 5 - 2 被构造为一个解释器树,并通过调用 Interpret 方法递归地盘算出效果。NumberExpression 是闭幕符表达式,用于表示具体的数字值,AddExpression 和 SubtractExpression 黑白闭幕符表达式,用于表示加法和减法操作。
2.15.4 特点


2.15.5 适用场景


2.15.6 总结

解释器模式通过定义语言的语法规则,并使用这些规则剖析和执行语句。它适用于简单的语法规则和小型语言剖析任务,但不适用于复杂的语法剖析和大规模体系。解释器模式的灵活性和扩展性使其在某些范畴特定语言的实现中非常有效。
2.16 迭代器模式(Iterator Pattern)

2.16.1 定义

迭代器模式的焦点头脑是提供一种统一的接口来遍历聚合对象中的元素,而不需要相识聚合对象的内部结构。通过这种方式,聚集和遍历算法之间解耦,遍历的方式可以更轻易地改变或扩展。
2.16.2 结构

迭代器模式包罗以下角色:

UML 类图
  1. +-------------------------------+       +-------------------+
  2. |   Aggregate                   |       |     Iterator      |
  3. +-------------------------------+       +-------------------+
  4. | + CreateIterator(): Iterator  |       | + HasNext(): bool |
  5. +-------------------------------+       | + Next(): T       |
  6.         ^                               | + Current(): T    |
  7.         |                               +-------------------+
  8. +-------------------------------+
  9. |ConcreteAggregate              |       +-------------------+
  10. +-------------------------------+       | ConcreteIterator  |
  11. | + CreateIterator(): Iterator  |       | + HasNext(): bool |
  12. +-------------------------------+       | + Next(): T       |
  13.                                         | + Current(): T    |
  14.                                         +-------------------+
复制代码
2.16.3 示例代码

假设我们要实现一个自定义的 List 聚集,并为它提供一个迭代器来遍历其中的元素。
迭代器接口
  1. // 迭代器接口
  2. public interface IIterator<T>
  3. {
  4.     bool HasNext();
  5.     T Next();
  6.     T Current { get; }
  7. }
复制代码
具体迭代器
  1. // 具体迭代器
  2. public class ListIterator<T> : IIterator<T>
  3. {
  4.     private readonly List<T> _list;
  5.     private int _position = 0;
  6.     public ListIterator(List<T> list)
  7.     {
  8.         _list = list;
  9.     }
  10.     public bool HasNext()
  11.     {
  12.         return _position < _list.Count;
  13.     }
  14.     public T Next()
  15.     {
  16.         return _list[_position++];
  17.     }
  18.     public T Current => _list[_position];
  19. }
复制代码
聚合接口
  1. // 聚合接口
  2. public interface IAggregate<T>
  3. {
  4.     IIterator<T> CreateIterator();
  5. }
复制代码
具体聚合类
  1. // 具体聚合类
  2. public class CustomList<T> : IAggregate<T>
  3. {
  4.     private readonly List<T> _items = new List<T>();
  5.     public void Add(T item)
  6.     {
  7.         _items.Add(item);
  8.     }
  9.     public IIterator<T> CreateIterator()
  10.     {
  11.         return new ListIterator<T>(_items);
  12.     }
  13. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建聚合对象并添加元素
  6.         CustomList<string> list = new CustomList<string>();
  7.         list.Add("Item 1");
  8.         list.Add("Item 2");
  9.         list.Add("Item 3");
  10.         // 创建迭代器并遍历元素
  11.         IIterator<string> iterator = list.CreateIterator();
  12.         while (iterator.HasNext())
  13.         {
  14.             string item = iterator.Next();
  15.             Console.WriteLine(item);
  16.         }
  17.     }
  18. }
复制代码
运行效果
  1. Item 1
  2. Item 2
  3. Item 3
复制代码
在这个例子中,我们创建了一个自定义的 CustomList 类,并为其提供了 ListIterator 作为具体的迭代器。ListIterator 实现了遍历列表元素的逻辑。客户端代码通过迭代器接口来遍历 CustomList 中的元素,而无需相识 CustomList 的内部结构。
2.16.4 特点


2.16.5 适用场景


2.16.6 总结

迭代器模式提供了一种遍历聚合对象的标准方法,通过解耦遍历逻辑和聚合对象的实现,增强了体系的灵活性和可扩展性。该模式特别得当需要在不暴露对象内部结构的环境下对对象举行遍历的场景。
2.17 中介者模式(Mediator Pattern)

2.17.1 定义

中介者模式将体系中多个对象之间复杂的交互和依赖关系抽象为一个中介者对象,各个对象不直接引用彼此,而是通过中介者举行通信。这样做可以减少对象之间的直接依赖,从而使体系更加易于维护和扩展。
2.17.2 结构

中介者模式包罗以下角色:

UML 类图
  1.                 +---------------------------------------------------+
  2.                 |     Mediator                                      |
  3.                 +---------------------------------------------------+
  4.                 | + Notify(sender: Colleague, event: string): void  |
  5.                 +---------------------------------------------------+
  6.                                          ^
  7.                                          |
  8.                 +---------------------------------------------------+
  9.                 |ConcreteMediator                                   |
  10.                 +---------------------------------------------------+
  11.                 | + Notify(sender: Colleague, event: string): void  |
  12.                 | + RegisterColleague(colleague: Colleague): void   |
  13.                 +---------------------------------------------------+
  14.                     +-------------------------------------------+
  15.                     |    Colleague                              |
  16.                     +-------------------------------------------+
  17.                     | + SetMediator(mediator: Mediator): void   |
  18.                     | + Send(event: string): void               |
  19.                     +-------------------------------------------+
  20.                          ^                                ^
  21.                          |                                |
  22. +-------------------------------+                  +-------------------------------+
  23. | ColleagueA                    |                  |  ColleagueB                   |
  24. +-------------------------------+                  +-------------------------------+
  25. | + Send(event: string): void   |                  | + Send(event: string): void   |
  26. +-------------------------------+                  +-------------------------------+
复制代码
2.17.3 示例代码

假设我们要实现一个谈天室体系,其中用户可以通过谈天室中介者互相发送消息。
中介者接口
  1. // 中介者接口
  2. public interface IChatMediator
  3. {
  4.     void SendMessage(string message, User user);
  5.     void RegisterUser(User user);
  6. }
复制代码
具体中介者
  1. // 具体中介者
  2. public class ChatMediator : IChatMediator
  3. {
  4.     private readonly List<User> _users = new List<User>();
  5.     public void RegisterUser(User user)
  6.     {
  7.         _users.Add(user);
  8.     }
  9.     public void SendMessage(string message, User sender)
  10.     {
  11.         foreach (var user in _users)
  12.         {
  13.             // 不要发给自己
  14.             if (user != sender)
  15.             {
  16.                 user.Receive(message);
  17.             }
  18.         }
  19.     }
  20. }
复制代码
同事类
  1. // 同事类
  2. public abstract class User
  3. {
  4.     protected IChatMediator _mediator;
  5.     protected string _name;
  6.     public User(IChatMediator mediator, string name)
  7.     {
  8.         _mediator = mediator;
  9.         _name = name;
  10.     }
  11.     public abstract void Send(string message);
  12.     public abstract void Receive(string message);
  13. }
  14. // 具体同事类
  15. public class ConcreteUser : User
  16. {
  17.     public ConcreteUser(IChatMediator mediator, string name) : base(mediator, name)
  18.     {
  19.     }
  20.     public override void Send(string message)
  21.     {
  22.         Console.WriteLine($"{_name} sends: {message}");
  23.         _mediator.SendMessage(message, this);
  24.     }
  25.     public override void Receive(string message)
  26.     {
  27.         Console.WriteLine($"{_name} receives: {message}");
  28.     }
  29. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         IChatMediator chatMediator = new ChatMediator();
  6.         User user1 = new ConcreteUser(chatMediator, "User1");
  7.         User user2 = new ConcreteUser(chatMediator, "User2");
  8.         User user3 = new ConcreteUser(chatMediator, "User3");
  9.         chatMediator.RegisterUser(user1);
  10.         chatMediator.RegisterUser(user2);
  11.         chatMediator.RegisterUser(user3);
  12.         user1.Send("Hello, everyone!");
  13.     }
  14. }
复制代码
运行效果
  1. User1 sends: Hello, everyone!
  2. User2 receives: Hello, everyone!
  3. User3 receives: Hello, everyone!
复制代码
在这个例子中,ChatMediator 是中介者,负责协调 User 对象之间的通信。用户通过调用中介者的 SendMessage 方法来发送消息,中介者会将消息转发给其他用户。
2.17.4 特点


2.17.5 适用场景


2.17.6 总结

中介者模式通过引入中介者对象来协调多个对象之间的交互,减少了对象之间的耦合度,并使体系更具可维护性和可扩展性。尽管中介者模式能够简化对象的交互逻辑,但需要注意中介者对象的复杂性管理,以避免其变得过于巨大。
2.18 备忘录模式(Memento Pattern)

2.18.1 定义

备忘录模式的焦点头脑是将对象的状态生存在一个备忘录对象中,并允许在未来的某个时刻恢复该状态。备忘录模式保证了状态的封装性,外部对象无法直接访问备忘录中的内容,从而掩护了原发器对象的内部细节。
2.18.2 结构

备忘录模式包罗以下角色:

UML 类图
  1. +---------------------------------------+      
  2. |  Originator                           |      
  3. +---------------------------------------+     
  4. | - state: String                       |   
  5. | + CreateMemento(): Memento            |  
  6. | + SetMemento(memento: Memento): void  |  
  7. +---------------------------------------+     
  8.         |                          
  9.         |                          
  10. +-----------------------+           +-----------------------+
  11. |   Memento             |           |   Caretaker           |
  12. +-----------------------+           +-----------------------+
  13. | - state: String       |           | - memento: Memento    |
  14. | + GetState(): String  |           +-----------------------+
  15. +-----------------------+     
复制代码
2.18.3 示例代码

假设我们要实现一个简单的文本编辑器,它能够生存文本的状态,并在需要时撤销或恢复状态。
原发器
  1. // 原发器类
  2. public class TextEditor
  3. {
  4.     private string _text;
  5.     public void SetText(string text)
  6.     {
  7.         _text = text;
  8.     }
  9.     public string GetText()
  10.     {
  11.         return _text;
  12.     }
  13.     public Memento CreateMemento()
  14.     {
  15.         return new Memento(_text);
  16.     }
  17.     public void RestoreMemento(Memento memento)
  18.     {
  19.         _text = memento.GetState();
  20.     }
  21. }
复制代码
备忘录
  1. // 备忘录类
  2. public class Memento
  3. {
  4.     private readonly string _state;
  5.     public Memento(string state)
  6.     {
  7.         _state = state;
  8.     }
  9.     public string GetState()
  10.     {
  11.         return _state;
  12.     }
  13. }
复制代码
负责人
  1. // 负责人类
  2. public class Caretaker
  3. {
  4.     private readonly Stack<Memento> _mementos = new Stack<Memento>();
  5.     public void SaveMemento(Memento memento)
  6.     {
  7.         _mementos.Push(memento);
  8.     }
  9.     public Memento GetMemento()
  10.     {
  11.         if (_mementos.Count > 0)
  12.         {
  13.             return _mementos.Pop();
  14.         }
  15.         return null;
  16.     }
  17. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         TextEditor editor = new TextEditor();
  6.         Caretaker caretaker = new Caretaker();
  7.         editor.SetText("Version 1");
  8.         caretaker.SaveMemento(editor.CreateMemento());
  9.         editor.SetText("Version 2");
  10.         caretaker.SaveMemento(editor.CreateMemento());
  11.         editor.SetText("Version 3");
  12.         Console.WriteLine("Current Text: " + editor.GetText());
  13.         editor.RestoreMemento(caretaker.GetMemento());
  14.         Console.WriteLine("Restored Text: " + editor.GetText());
  15.         editor.RestoreMemento(caretaker.GetMemento());
  16.         Console.WriteLine("Restored Text: " + editor.GetText());
  17.     }
  18. }
复制代码
运行效果
  1. Current Text: Version 3
  2. Restored Text: Version 2
  3. Restored Text: Version 1
复制代码
在这个例子中,TextEditor 是原发器,负责创建和恢复文本的状态;Memento 是备忘录,生存文本的状态;Caretaker 是负责人,管理备忘录的存储和恢复。在运行过程中,我们生存了多个文本状态,并通过恢复操作撤销了修改,返回到之前的状态。
2.18.4 特点


2.18.5 适用场景


2.18.6 总结

备忘录模式通过生存对象的状态,提供了恢复该状态的机制。它通过封装状态,确保了对象内部细节的掩护,同时又允许状态的恢复。该模式非常得当用于实现“撤销/恢复”功能,并在需要管理复杂状态变动的场景中提供了很好的办理方案。
2.19 观察者模式(Observer Pattern)

2.19.1 定义

观察者模式的焦点头脑是当一个对象(被观察者)的状态改变时,所有依赖于它的对象(观察者)都会被关照并更新。这样一来,观察者模式实现了对象之间的松散耦合,使得一个对象的变化可以主动地传播到相关的对象。
2.19.2 结构

观察者模式包罗以下角色:

UML 类图
  1. +---------------------------+         +-------------------+
  2. |     Subject               | <------ |     Observer      |
  3. +---------------------------+         +-------------------+
  4. | + Attach(obs: Observer)   |         | + Update(): void  |
  5. | + Detach(obs: Observer)   |         +-------------------+
  6. | + Notify(): void          |               ^
  7. +---------------------------+               |
  8.         ^                                   |
  9.         |                                   |
  10. +-----------------------+             +-------------------+
  11. | ConcreteSubject       |             | ConcreteObserver  |
  12. +-----------------------+             +-------------------+
  13. | - state: State        |             | - state: State    |
  14. | + GetState(): State   |             | + Update(): void  |
  15. | + SetState(State)     |             +-------------------+
  16. +-----------------------+
复制代码
2.19.3 示例代码

假设我们要实现一个天气站体系,天气站会记录当前的天气信息,并关照注册的体现设备(如手机应用、网站等)举行更新。
观察者接口
  1. // 观察者接口
  2. public interface IObserver
  3. {
  4.     void Update(string temperature, string humidity, string pressure);
  5. }
复制代码
主题接口
  1. // 主题接口
  2. public interface ISubject
  3. {
  4.     void RegisterObserver(IObserver observer);
  5.     void RemoveObserver(IObserver observer);
  6.     void NotifyObservers();
  7. }
复制代码
具体主题
  1. // 具体主题
  2. public class WeatherStation : ISubject
  3. {
  4.     private List<IObserver> _observers;
  5.     private string _temperature;
  6.     private string _humidity;
  7.     private string _pressure;
  8.     public WeatherStation()
  9.     {
  10.         _observers = new List<IObserver>();
  11.     }
  12.     public void RegisterObserver(IObserver observer)
  13.     {
  14.         _observers.Add(observer);
  15.     }
  16.     public void RemoveObserver(IObserver observer)
  17.     {
  18.         _observers.Remove(observer);
  19.     }
  20.     public void NotifyObservers()
  21.     {
  22.         foreach (var observer in _observers)
  23.         {
  24.             observer.Update(_temperature, _humidity, _pressure);
  25.         }
  26.     }
  27.     public void SetMeasurements(string temperature, string humidity, string pressure)
  28.     {
  29.         _temperature = temperature;
  30.         _humidity = humidity;
  31.         _pressure = pressure;
  32.         NotifyObservers();
  33.     }
  34. }
复制代码
具体观察者
  1. // 具体观察者
  2. public class PhoneDisplay : IObserver
  3. {
  4.     private string _temperature;
  5.     private string _humidity;
  6.     private string _pressure;
  7.     public void Update(string temperature, string humidity, string pressure)
  8.     {
  9.         _temperature = temperature;
  10.         _humidity = humidity;
  11.         _pressure = pressure;
  12.         Display();
  13.     }
  14.     public void Display()
  15.     {
  16.         Console.WriteLine($"Phone Display -> Temperature: {_temperature}, Humidity: {_humidity}, Pressure: {_pressure}");
  17.     }
  18. }
  19. public class WebDisplay : IObserver
  20. {
  21.     private string _temperature;
  22.     private string _humidity;
  23.     private string _pressure;
  24.     public void Update(string temperature, string humidity, string pressure)
  25.     {
  26.         _temperature = temperature;
  27.         _humidity = humidity;
  28.         _pressure = pressure;
  29.         Display();
  30.     }
  31.     public void Display()
  32.     {
  33.         Console.WriteLine($"Web Display -> Temperature: {_temperature}, Humidity: {_humidity}, Pressure: {_pressure}");
  34.     }
  35. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         WeatherStation weatherStation = new WeatherStation();
  6.         IObserver phoneDisplay = new PhoneDisplay();
  7.         IObserver webDisplay = new WebDisplay();
  8.         weatherStation.RegisterObserver(phoneDisplay);
  9.         weatherStation.RegisterObserver(webDisplay);
  10.         weatherStation.SetMeasurements("30°C", "65%", "1013 hPa");
  11.         weatherStation.RemoveObserver(phoneDisplay);
  12.         weatherStation.SetMeasurements("28°C", "70%", "1012 hPa");
  13.     }
  14. }
复制代码
运行效果
  1. Phone Display -> Temperature: 30°C, Humidity: 65%, Pressure: 1013 hPa
  2. Web Display -> Temperature: 30°C, Humidity: 65%, Pressure: 1013 hPa
  3. Web Display -> Temperature: 28°C, Humidity: 70%, Pressure: 1012 hPa
复制代码
在这个例子中,WeatherStation 是具体的主题,当天气数据发生变化时,它关照所有注册的观察者(如 PhoneDisplay 和 WebDisplay)举行更新并体现新的数据。
2.19.4 特点


2.19.5 适用场景


2.19.6 总结

观察者模式通过定义一对多的依赖关系,实现了对象间的松散耦合和动态通信。它允许对象主动关照相关的依赖对象并更新状态,非常得当用于事件驱动的体系和需要动态更新的场景。尽管大概会带来一定的关照开销和复杂性管理,但它依然是实现对象间动态通信的强盛工具。
2.20 状态模式(State Pattern)

2.20.1 定义

状态模式的焦点头脑是将与状态相关的行为封装在独立的状态对象中,并通过状态对象来管理对象的状态转换。这样,原始对象在其状态发生变化时,会主动切换到对应的状态对象,从而体现出不同的行为。
2.20.2 结构

状态模式包罗以下角色:

UML 类图
  1. +-------------------+       +-----------------------------------+
  2. |      Context      |       |       State                       |
  3. +-------------------+       +-----------------------------------+
  4. | - state: State    |<------| + Handle(context: Context): void  |
  5. | + Request(): void |       +-----------------------------------+
  6. +-------------------+            ^                     ^
  7.                                  |                     |
  8.                                  |                     |
  9.     +-----------------------------------+        +-----------------------------------+
  10.     | ConcreteStateA                    |        | ConcreteStateB                    |
  11.     +-----------------------------------+        +-----------------------------------+
  12.     | + Handle(context: Context): void  |        | + Handle(context: Context): void  |
  13.     +-----------------------------------+        +-----------------------------------+
复制代码
2.20.3 示例代码

假设我们要实现一个简单的电灯开关体系,电灯可以处于“开”和“关”两种状态,并且根据当前的状态来执行不同的操作。
状态接口
  1. // 状态接口
  2. public interface IState
  3. {
  4.     void Handle(Context context);
  5. }
复制代码
具体状态类
  1. // 具体状态 - 开灯状态
  2. public class OnState : IState
  3. {
  4.     public void Handle(Context context)
  5.     {
  6.         Console.WriteLine("The light is already ON.");
  7.         context.SetState(new OffState());
  8.     }
  9. }
  10. // 具体状态 - 关灯状态
  11. public class OffState : IState
  12. {
  13.     public void Handle(Context context)
  14.     {
  15.         Console.WriteLine("The light is OFF. Turning it ON.");
  16.         context.SetState(new OnState());
  17.     }
  18. }
复制代码
上下文类
  1. // 上下文类
  2. public class Context
  3. {
  4.     private IState _state;
  5.     public Context(IState state)
  6.     {
  7.         _state = state;
  8.     }
  9.     public void SetState(IState state)
  10.     {
  11.         _state = state;
  12.     }
  13.     public void Request()
  14.     {
  15.         _state.Handle(this);
  16.     }
  17. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         Context context = new Context(new OffState());
  6.         // 初始状态为关灯状态
  7.         context.Request(); // 关灯 -> 开灯
  8.         // 再次请求
  9.         context.Request(); // 开灯 -> 关灯
  10.         // 再次请求
  11.         context.Request(); // 关灯 -> 开灯
  12.     }
  13. }
复制代码
运行效果
  1. The light is OFF. Turning it ON.
  2. The light is already ON.
  3. The light is OFF. Turning it ON.
复制代码
在这个例子中,Context 类维护一个当前状态,当调用 Request() 方法时,会根据当前状态执行相应的操作并切换到下一个状态。OnState 和 OffState 是两种具体的状态类,分别定义了在不同状态下的行为。
2.20.4 特点


2.20.5 适用场景


2.20.6 总结

状态模式通过将状态相关的行为封装在独立的状态对象中,简化了对象的状态管理逻辑。它消除了大量的条件分支语句,使代码更加清晰和易于扩展。尽管状态模式大概会增加类的数量,但它为管理复杂的状态转换逻辑提供了一种灵活且有效的办理方案。
2.21 战略模式(Strategy Pattern)

2.21.1 定义

战略模式的焦点头脑是将不同的算法或行为封装到独立的战略类中,并通过上下文类来管理和使用这些战略。客户端可以通过上下文类来动态选择使用哪种战略,而无需关心战略的具体实现细节。
2.21.2 结构

战略模式包罗以下角色:

UML 类图
  1. +---------------------------+       +-----------------------+
  2. |      Context              |       |      Strategy         |
  3. +---------------------------+       +-----------------------+
  4. | - strategy: Strategy      |       | + Algorithm(): void   |
  5. | + SetStrategy(Strategy)   |       +-----------------------+
  6. | + ExecuteStrategy(): void |           ^              ^
  7. +---------------------------+           |              |
  8.                                         |              |
  9.                                         |              |
  10.                    +-----------------------+        +-----------------------+
  11.                    | ConcreteStrategyA     |        | ConcreteStrategyB     |
  12.                    +-----------------------+        +-----------------------+
  13.                    | + Algorithm(): void   |        | + Algorithm(): void   |
  14.                    +-----------------------+        +-----------------------+
复制代码
2.21.3 示例代码

假设我们要实现一个简单的付出体系,它支持多种付出方式,如信用卡付出、PayPal付出和比特币付出。我们可以使用战略模式来封装这些付出方式,并让客户端在运行时选择不同的付出战略。
战略接口
  1. // 策略接口
  2. public interface IPaymentStrategy
  3. {
  4.     void Pay(double amount);
  5. }
复制代码
具体战略类
  1. // 具体策略 - 信用卡支付
  2. public class CreditCardPayment : IPaymentStrategy
  3. {
  4.     private string _cardNumber;
  5.     public CreditCardPayment(string cardNumber)
  6.     {
  7.         _cardNumber = cardNumber;
  8.     }
  9.     public void Pay(double amount)
  10.     {
  11.         Console.WriteLine($"Paid {amount} using Credit Card {_cardNumber}.");
  12.     }
  13. }
  14. // 具体策略 - PayPal支付
  15. public class PayPalPayment : IPaymentStrategy
  16. {
  17.     private string _email;
  18.     public PayPalPayment(string email)
  19.     {
  20.         _email = email;
  21.     }
  22.     public void Pay(double amount)
  23.     {
  24.         Console.WriteLine($"Paid {amount} using PayPal account {_email}.");
  25.     }
  26. }
  27. // 具体策略 - 比特币支付
  28. public class BitcoinPayment : IPaymentStrategy
  29. {
  30.     private string _walletAddress;
  31.     public BitcoinPayment(string walletAddress)
  32.     {
  33.         _walletAddress = walletAddress;
  34.     }
  35.     public void Pay(double amount)
  36.     {
  37.         Console.WriteLine($"Paid {amount} using Bitcoin wallet {_walletAddress}.");
  38.     }
  39. }
复制代码
上下文类
  1. // 上下文类
  2. public class PaymentContext
  3. {
  4.     private IPaymentStrategy _paymentStrategy;
  5.     public void SetPaymentStrategy(IPaymentStrategy paymentStrategy)
  6.     {
  7.         _paymentStrategy = paymentStrategy;
  8.     }
  9.     public void Pay(double amount)
  10.     {
  11.         _paymentStrategy.Pay(amount);
  12.     }
  13. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         PaymentContext context = new PaymentContext();
  6.         // 使用信用卡支付
  7.         context.SetPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456"));
  8.         context.Pay(100.0);
  9.         // 使用PayPal支付
  10.         context.SetPaymentStrategy(new PayPalPayment("user@example.com"));
  11.         context.Pay(200.0);
  12.         // 使用比特币支付
  13.         context.SetPaymentStrategy(new BitcoinPayment("1BitcoinAddressXYZ"));
  14.         context.Pay(300.0);
  15.     }
  16. }
复制代码
运行效果
  1. Paid 100 using Credit Card 1234-5678-9012-3456.
  2. Paid 200 using PayPal account user@example.com.
  3. Paid 300 using Bitcoin wallet 1BitcoinAddressXYZ.
复制代码
在这个例子中,PaymentContext 是上下文类,它持有一个 IPaymentStrategy 战略接口的引用。客户端可以动态设置不同的付出战略,如 CreditCardPayment、PayPalPayment 和 BitcoinPayment,并通过 Pay() 方法执行付出操作。这样,付出方式的变化不会影响客户端代码。
2.21.4 特点


2.21.5 适用场景


2.21.6 总结

战略模式通过将不同的算法封装到独立的战略类中,实现了算法的灵活互换。它消除了大量的条件分支语句,使代码更加清晰和可扩展。尽管战略模式大概会增加类的数量,但它为体系的算法选择和扩展提供了一种灵活且强盛的办理方案。在需要灵活选择算法或行为的场景中,战略模式是一种非常有效的计划模式。
2.22 模板方法模式(Template Method Pattern)

2.22.1 定义

模板方法模式通过在基类中定义一个模板方法,该方法封装了一个算法的固定步骤,然后允许子类实现或重写这些步骤。这样,子类可以定制算法的具体行为,而无需改变算法的团体结构。
2.22.2 结构

模板方法模式包罗以下角色:

UML 类图
  1. +---------------------------+     
  2. |  AbstractClass            |     
  3. +---------------------------+     
  4. | + TemplateMethod(): void  |     
  5. | + Step1(): void           |     
  6. | + Step2(): void           |     
  7. | - Step3(): void           |     
  8. +---------------------------+     
  9.         ^     
  10.         |     
  11. +-------------------+     
  12. |  ConcreteClass    |     
  13. +-------------------+     
  14. | - Step3(): void   |     
  15. +-------------------+
复制代码
2.22.3 示例代码

假设我们要制作一杯饮料,制作的过程包括煮水、冲泡、倒入杯中、添加配料等步骤。咖啡和茶是两种不同的饮料,它们在制作过程中的步骤根本相同,但在某些步骤上有所不同。我们可以使用模板方法模式来实现这个场景。
抽象类
  1. // 抽象类 - 饮料制作过程
  2. public abstract class Beverage
  3. {
  4.     // 模板方法
  5.     public void PrepareRecipe()
  6.     {
  7.         BoilWater();
  8.         Brew();
  9.         PourInCup();
  10.         AddCondiments();
  11.     }
  12.     // 具体方法 - 煮水
  13.     private void BoilWater()
  14.     {
  15.         Console.WriteLine("Boiling water");
  16.     }
  17.     // 抽象方法 - 冲泡
  18.     protected abstract void Brew();
  19.     // 具体方法 - 倒入杯中
  20.     private void PourInCup()
  21.     {
  22.         Console.WriteLine("Pouring into cup");
  23.     }
  24.     // 抽象方法 - 添加配料
  25.     protected abstract void AddCondiments();
  26. }
复制代码
具体类
  1. // 具体类 - 茶
  2. public class Tea : Beverage
  3. {
  4.     protected override void Brew()
  5.     {
  6.         Console.WriteLine("Steeping the tea");
  7.     }
  8.     protected override void AddCondiments()
  9.     {
  10.         Console.WriteLine("Adding lemon");
  11.     }
  12. }
  13. // 具体类 - 咖啡
  14. public class Coffee : Beverage
  15. {
  16.     protected override void Brew()
  17.     {
  18.         Console.WriteLine("Dripping coffee through filter");
  19.     }
  20.     protected override void AddCondiments()
  21.     {
  22.         Console.WriteLine("Adding sugar and milk");
  23.     }
  24. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         Beverage tea = new Tea();
  6.         tea.PrepareRecipe();  // 制作茶
  7.         Console.WriteLine();
  8.         Beverage coffee = new Coffee();
  9.         coffee.PrepareRecipe();  // 制作咖啡
  10.     }
  11. }
复制代码
运行效果
  1. Boiling water
  2. Steeping the tea
  3. Pouring into cup
  4. Adding lemon
  5. Boiling water
  6. Dripping coffee through filter
  7. Pouring into cup
  8. Adding sugar and milk
复制代码
在这个例子中,Beverage 是抽象类,定义了一个模板方法 PrepareRecipe(),它包罗了制作饮料的固定步骤。这些步骤中,有些是具体实现的(如 BoilWater() 和 PourInCup()),而有些是抽象方法,由子类 Tea 和 Coffee 来实现(如 Brew() 和 AddCondiments())。客户端代码可以使用不同的具体类来制作不同的饮料,而不需要关心具体的实现细节。
2.22.4 特点


2.22.5 适用场景


2.22.6 总结

模板方法模式通过将通用的算法步骤封装到抽象类中,允许子类重写或扩展特定的步骤,实现了算法的复用和扩展。它确保了算法的团体结构不被粉碎,同时为子类提供了灵活性。在多个类具有相似的操作步骤时,模板方法模式是一种非常有效的计划模式。
2.23 访问者模式(Visitor Pattern)

2.23.1 定义

访问者模式通过引入一个访问者接口,使得你可以在元素类中接受访问者,并让访问者决定对元素的具体操作。访问者模式的关键在于分离算法和数据结构,使得新的操作可以轻松地添加而不影响已有的数据结构。
2.23.2 结构

访问者模式包罗以下角色:

UML 类图
  1. +---------------------------+         +---------------------------+
  2. |      Visitor              | <------ |     Element               |
  3. +---------------------------+         +---------------------------+
  4. | + VisitElementA():void    |         | + Accept(v:Visitor): void |
  5. | + VisitElementB():void    |         +---------------------------+
  6. +---------------------------+               ^
  7.         ^                                   |
  8.         |                                   |
  9. +---------------------------+         +---------------------------+
  10. | ConcreteVisitor           |         | ConcreteElement           |
  11. +---------------------------+         +---------------------------+
  12. | + VisitElementA():void    |         | + Accept(v:Visitor): void |
  13. | + VisitElementB():void    |         | + OperationA(): void      |
  14. +---------------------------+         +---------------------------+
复制代码
2.23.3 示例代码

假设我们要实现一个报表体系,体系中包罗不同范例的员工(如工程师和司理),每种员工有不同的报表要求。我们可以使用访问者模式来实现报表的天生,使得报表的天生与员工范例的实现分离。
访问者接口
  1. // 访问者接口
  2. public interface IVisitor
  3. {
  4.     void Visit(Engineer engineer);
  5.     void Visit(Manager manager);
  6. }
复制代码
具体访问者
  1. // 具体访问者 - 报表生成器
  2. public class ReportGenerator : IVisitor
  3. {
  4.     public void Visit(Engineer engineer)
  5.     {
  6.         Console.WriteLine($"Generating report for Engineer: {engineer.Name}");
  7.     }
  8.     public void Visit(Manager manager)
  9.     {
  10.         Console.WriteLine($"Generating report for Manager: {manager.Name} with {manager.SubordinatesCount} subordinates.");
  11.     }
  12. }
复制代码
元素接口
  1. // 元素接口
  2. public interface IEmployee
  3. {
  4.     void Accept(IVisitor visitor);
  5. }
复制代码
具体元素类
  1. // 具体元素 - 工程师
  2. public class Engineer : IEmployee
  3. {
  4.     public string Name { get; private set; }
  5.     public Engineer(string name)
  6.     {
  7.         Name = name;
  8.     }
  9.     public void Accept(IVisitor visitor)
  10.     {
  11.         visitor.Visit(this);
  12.     }
  13. }
  14. // 具体元素 - 经理
  15. public class Manager : IEmployee
  16. {
  17.     public string Name { get; private set; }
  18.     public int SubordinatesCount { get; private set; }
  19.     public Manager(string name, int subordinatesCount)
  20.     {
  21.         Name = name;
  22.         SubordinatesCount = subordinatesCount;
  23.     }
  24.     public void Accept(IVisitor visitor)
  25.     {
  26.         visitor.Visit(this);
  27.     }
  28. }
复制代码
对象结构
  1. // 对象结构 - 员工列表
  2. public class EmployeeStructure
  3. {
  4.     private List<IEmployee> _employees = new List<IEmployee>();
  5.     public void Attach(IEmployee employee)
  6.     {
  7.         _employees.Add(employee);
  8.     }
  9.     public void Detach(IEmployee employee)
  10.     {
  11.         _employees.Remove(employee);
  12.     }
  13.     public void Accept(IVisitor visitor)
  14.     {
  15.         foreach (var employee in _employees)
  16.         {
  17.             employee.Accept(visitor);
  18.         }
  19.     }
  20. }
复制代码
客户端代码
  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         // 创建员工结构
  6.         EmployeeStructure employeeStructure = new EmployeeStructure();
  7.         // 添加员工
  8.         employeeStructure.Attach(new Engineer("John"));
  9.         employeeStructure.Attach(new Manager("Alice", 5));
  10.         // 创建报表生成器
  11.         ReportGenerator reportGenerator = new ReportGenerator();
  12.         // 生成报表
  13.         employeeStructure.Accept(reportGenerator);
  14.     }
  15. }
复制代码
运行效果
  1. Generating report for Engineer: John
  2. Generating report for Manager: Alice with 5 subordinates.
复制代码
在这个例子中,IVisitor 定义了对不同员工范例(Engineer 和 Manager)的访问方法。ReportGenerator 是具体的访问者,实现了天生报表的逻辑。IEmployee 接口定义了 Accept 方法,Engineer 和 Manager 作为具体的元素,实现了接受访问者的逻辑。EmployeeStructure 作为对象结构,管理了所有的员工,并允许访问者访问这些员工。
2.23.4 特点


2.23.5 适用场景


2.23.6 总结

访问者模式通过将操作分离到独立的访问者对象中,使得在不修改元素类的环境下,可以增加新的操作。它适用于对象结构稳固但操作经常变化的场景。然而,由于需要对每个元素类增加接受访问者的方法,并且大概导致违背开闭原则,因此在使用时需要衡量利弊。在需要对复杂对象结构举行扩展和管理时,访问者模式是一种强盛的计划模式。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




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