CSharp-设计模式

杜绝屎山,从我做起!

资源

  • 设计模式 | 菜鸟教程 这个教程使用 Java 写的,但是我并没有系统性地学过 Java,真是太不幸运了!所以我决定用 C# 重写一遍。

C#

配置

众所周知,VSC 是世界上最好的 IDE……

VSC 中安装完 C#、C# Extensions 插件后,在一个空项目中创建脚手架:

shell
dotnet new console

编写完代码后按 F5 进入调试模式。

C# 一些特性

  • abstract:用于在基类中定义没有实现的方法,要求子类必须实现它。

  • override:用于在子类中重写基类中已经实现的方法,提供不同的实现。

  • interface:是一种定义契约的机制,它指定了实现类必须遵循的一组方法、属性、事件和索引器的签名,但不提供具体的实现。

面向对象编程

封装、继承和多态是面向对象编程(OOP)的三大核心概念,通常用于设计和实现更灵活、可维护的代码。

封装(Encapsulation)

  • 封装是将数据(属性)和操作数据的方法(函数)捆绑在一起,并对外隐藏内部实现细节。外界只能通过公共接口访问对象的状态,而不能直接修改对象的内部数据。
  • 目的是保护对象的内部数据不被外界随意修改,确保对象的状态始终合法。
  • 例如,定义一个类 Car,其中有一个私有属性 speed,并通过公共方法 accelerate() 和 brake() 来操作该属性。
c#
public class Car
{
    private int speed;  // 私有属性
    
    public void Accelerate()
    {
        speed += 10;  // 修改属性的方法
    }
    
    public int GetSpeed()
    {
        return speed;  // 获取属性的方法
    }
}

继承(Inheritance)

  • 继承是从现有类创建新类的机制,新类称为子类,现有类称为父类。子类继承了父类的属性和方法,可以增加新的功能或者重写父类的功能。
  • 继承有助于代码的复用,避免重复定义相同的功能。
  • 例如,Car 类可以继承自 Vehicle 类,Vehicle 定义了一些通用的属性和方法,而 Car 可以扩展或修改这些功能。
c#
public class Vehicle
{
    public int speed;
    public void Move() { Console.WriteLine("Vehicle is moving"); }
}
 
public class Car : Vehicle  // 继承自 Vehicle
{
    public void Horn() { Console.WriteLine("Car is honking"); }
}

多态(Polymorphism)

  • 多态是指相同的操作作用于不同的对象上时,表现出不同的行为。多态分为编译时多态(方法重载)和运行时多态(方法重写)。
  • 通过多态,子类可以替代父类,执行不同的实现,从而提高灵活性和可扩展性。
  • 例如,Car 类和 Truck 类可以都有一个 Move() 方法,但它们可以有不同的实现。
c#
public class Vehicle
{
    public virtual void Move()
    {
        Console.WriteLine("Vehicle is moving");
    }
}
 
public class Car : Vehicle
{
    public override void Move()
    {
        Console.WriteLine("Car is moving");
    }
}
 
public class Truck : Vehicle
{
    public override void Move()
    {
        Console.WriteLine("Truck is moving");
    }
}
 
// 使用多态
Vehicle myVehicle = new Car();
myVehicle.Move();  // 输出: Car is moving

总结

  • 封装保护对象的内部数据,通过提供公共接口来操作数据。
  • 继承允许新类复用现有类的属性和方法,促进代码复用。
  • 多态使得相同的操作在不同的对象上产生不同的行为,提高代码的灵活性。

正文

设计模式的类型

根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:

  • 创建型模式(Creational Patterns)
    • 工厂模式(Factory Pattern)
    • 抽象工厂模式(Abstract Factory Pattern)
    • 单例模式(Singleton Pattern)
    • 建造者模式(Builder Pattern)
    • 原型模式(Prototype Pattern)

注意

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

  • 结构型模式(Structural Patterns)
    • 适配器模式(Adapter Pattern)
    • 桥接模式(Bridge Pattern)
    • 过滤器模式(Filter、Criteria Pattern)
    • 组合模式(Composite Pattern)
    • 装饰器模式(Decorator Pattern)
    • 外观模式(Facade Pattern)
    • 享元模式(Flyweight Pattern)
    • 代理模式(Proxy Pattern)

注意

这些模式关注对象之间的组合和关系,旨在解决如何构建灵活且可复用的类和对象结构。

  • 行为型模式(Behavioral Patterns)
    • 责任链模式(Chain of Responsibility Pattern)
    • 命令模式(Command Pattern)
    • 解释器模式(Interpreter Pattern)
    • 迭代器模式(Iterator Pattern)
    • 中介者模式(Mediator Pattern)
    • 备忘录模式(Memento Pattern)
    • 观察者模式(Observer Pattern)
    • 状态模式(State Pattern)
    • 空对象模式(Null Object Pattern)
    • 策略模式(Strategy Pattern)
    • 模板模式(Template Pattern)
    • 访问者模式(Visitor Pattern)

注意

这些模式关注对象之间的通信和交互,旨在解决对象之间的责任分配和算法的封装。

设计模式的六大原则

1. 单一职责原则(SRP)

注意

单一职责原则要求一个类只负责一个功能。如果一个类承担了多个职责,它应该被拆分为多个类。

2. 开放-封闭原则(OCP)

注意

开放-封闭原则要求对扩展开放,对修改封闭。我们可以通过继承或者接口来实现这个原则。

Mermaid
正在加载图表…

下面的例子违反了 OCP 原则:

c#
// 违反开放封闭原则
public class AreaCalculator
{
 public double CalculateArea(object shape)
 {
     if (shape is Circle)
     {
           Circle circle = (Circle)shape;
           return Math.PI * circle.Radius * circle.Radius;
     }
     else if (shape is Rectangle)
     {
           Rectangle rectangle = (Rectangle)shape;
           return rectangle.Width * rectangle.Height;
     }
 	return 0;
 }
}

3. 里氏替换原则(LSP)

注意

子类应该能够替代父类,而不会影响程序的正确性。

Mermaid
正在加载图表…
c#
// 违反里氏替换原则
public class Rectangle
{
    public virtual double Width { get; set; }
    public virtual double Height { get; set; }
    public double Area()
    {
        return Width * Height;
    }
}
 
public class Square : Rectangle
{
    public override double Width
    {
        set { base.Width = base.Height = value; }
    }
 
    public override double Height
    {
        set { base.Width = base.Height = value; }
    }
}

4. 接口隔离原则(ISP)

注意

接口应该只包含客户端需要的方法,不应该强迫实现不必要的功能。

Mermaid
正在加载图表…
c#
// 违反接口隔离原则
public interface IPrinter
{
    void Print();
    void Scan();
    void Fax();
}
 
public class BasicPrinter : IPrinter
{
    public void Print()
    {
        Console.WriteLine("Printing...");
    }
 
    public void Scan()
    {
        throw new NotImplementedException(); // BasicPrinter 不支持扫描
    }
 
    public void Fax()
    {
        throw new NotImplementedException(); // BasicPrinter 不支持传真
    }
}

5. 依赖倒转原则(DIP)

注意

高层模块不应依赖低层模块,两者都应依赖抽象。

Mermaid
正在加载图表…
c#
// 违反依赖倒转原则
public class FileReader
{
    public string Read()
    {
        return "Reading from file.";
    }
}
 
public class Application
{
    private FileReader _fileReader;
 
    public Application()
    {
        _fileReader = new FileReader();
    }
 
    public void Start()
    {
        Console.WriteLine(_fileReader.Read());
    }
}

6. 合成复用原则(CRP)

注意

优先使用组合而不是继承。

Mermaid
正在加载图表…
c#
// 违反合成复用原则
public class Engine
{
    public void Start()
    {
        Console.WriteLine("Engine starts");
    }
}
 
public class Car : Engine
{
    public void Drive()
    {
        Console.WriteLine("Car is driving");
    }
}

结构型模式(5)

工厂模式(Factory Pattern)

注意

工厂模式(Factory Pattern)提供了一种创建对象的方式,使得创建对象的过程与使用对象的过程分离。

应用实例

  1. 汽车制造:你需要一辆汽车,只需从工厂提货,而不需要关心汽车的制造过程及其内部实现。
  2. Hibernate:更换数据库时,只需更改方言(Dialect)和数据库驱动(Driver),即可实现对不同数据库的切换。

优点:

  1. 调用者只需要知道对象的名称即可创建对象。
  2. 扩展性高,如果需要增加新产品,只需扩展一个工厂类即可。
  3. 屏蔽了产品的具体实现,调用者只关心产品的接口。

缺点:

  1. 每次增加一个产品时,都需要增加一个具体类和对应的工厂,使系统中类的数量成倍增加,增加了系统的复杂度和具体类的依赖。
Mermaid
正在加载图表…

说明:

  1. 接口 Shape:定义了一个 Draw() 方法,所有实现该接口的类都需要提供 Draw() 方法的实现。
  2. Rectangle、Square、Circle:分别是 Shape 接口的实现类,每个类都实现了 Draw() 方法,输出各自的形状信息。
  3. ShapeFactory:工厂类,根据传入的 shapeType 字符串创建并返回相应的形状对象(Rectangle、Square 或 Circle)。
  4. FactoryPattenDemo:演示类,包含 Main 方法,创建 ShapeFactory 实例并使用其方法生成形状对象,最后调用 Draw() 方法输出信息。

类之间的关系:

  • Shape <|.. Rectangle, Shape <|.. Square, Shape <|.. Circle 表示 Rectangle、Square 和 Circle 都实现了 Shape 接口。
  • ShapeFactory --> Shape 表示 ShapeFactory 依赖于 Shape 类型,并通过 GetShape 方法返回相应的实现类。
c#
public interface Shape {
    void Draw();
}

抽象工厂模式(Abstract Factory Pattern)

注意

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

应用实例

  1. 汽车制造:你需要一辆汽车,只需从工厂提货,而不需要关心汽车的制造过程及其内部实现。
  2. Hibernate:更换数据库时,只需更改方言(Dialect)和数据库驱动(Driver),即可实现对不同数据库的切换。

优点

  1. 调用者只需要知道对象的名称即可创建对象。
  2. 扩展性高,如果需要增加新产品,只需扩展一个工厂类即可。
  3. 屏蔽了产品的具体实现,调用者只关心产品的接口。

缺点

每次增加一个产品时,都需要增加一个具体类和对应的工厂,使系统中类的数量成倍增加,增加了系统的复杂度和具体类的依赖。(emmm 所以我觉得这个有点蠢)

Mermaid
正在加载图表…

说明:

  1. Shape 和 Color 接口:
    • Shape 接口定义了 Draw() 方法,所有实现该接口的类需要提供该方法的具体实现。
    • Color 接口定义了 Fill() 方法,所有实现该接口的类需要提供该方法的具体实现。
  2. Rectangle、Square、Circle 类:
    • 这些类实现了 Shape 接口,并提供了 Draw() 方法的具体实现。
  3. Red、Green、Blue 类:
    • 这些类实现了 Color 接口,并提供了 Fill() 方法的具体实现。
  4. AbstractFactory 抽象类:
    • 定义了两个抽象方法 GetShape() 和 GetColor(),分别用于获取形状和颜色对象。
  5. ShapeFactory 和 ColorFactory 类:
    • 这些类继承自 AbstractFactory,并分别实现了 GetShape() 和 GetColor() 方法。ShapeFactory 负责创建形状对象,ColorFactory 负责创建颜色对象。
  6. FactoryProducer 类:
    • 这是一个工厂生产者类,根据传入的选择字符串返回一个相应的工厂实例(ShapeFactory 或 ColorFactory)。

类之间的关系:

  • Shape <|.. Rectangle, Shape <|.. Square, Shape <|.. Circle 表示 Rectangle、Square 和 Circle 都实现了 Shape 接口。
  • Color <|.. Red, Color <|.. Green, Color <|.. Blue 表示 Red、Green 和 Blue 都实现了 Color 接口。
  • AbstractFactory <|-- ShapeFactory 和 AbstractFactory <|-- ColorFactory 表示 ShapeFactory 和 ColorFactory 类继承自 AbstractFactory。
  • FactoryProducer --> AbstractFactory 表示 FactoryProducer 类依赖于 AbstractFactory,并通过 GetFactory() 方法返回一个相应的工厂实例。
c#
public interface Shape
{
    void Draw();
}

单例模式(Singleton Pattern)

注意

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。

注意:

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。

应用实例

  • 一个班级只有一个班主任。
  • Windows 在多进程多线程环境下操作文件时,避免多个进程或线程同时操作一个文件,需要通过唯一实例进行处理。
  • 设备管理器设计为单例模式,例如电脑有两台打印机,避免同时打印同一个文件。

优点

  • 内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时(如管理学院首页页面缓存)。
  • 避免资源的多重占用(如写文件操作)。

缺点

  • 没有接口,不能继承。
  • 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心实例化方式。
Mermaid
正在加载图表…
c#
public class SingleObject
{
    // 创建 SingleObject 的一个对象
    public static SingleObject instance = new SingleObject();
    // 让构造函数为 private,这样该类就不会被实例化
    private SingleObject() { }
    // 获取唯一可用的对象
    public static SingleObject getInstance()
    {
        return instance;
    }
 
    public void ShowMessage()
    {
        Console.WriteLine("Hello World!");
    }
}

建造者模式(Builder Pattern)

注意

建造者模式是一种创建型设计模式,它的主要目的是将一个复杂对象的构建过程与其表示相分离,从而可以创建具有不同表示形式的对象。

优点

  • 分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
  • 可以更好地控制构建过程,隐藏具体构建细节。
  • 代码复用性高,可以在不同的构建过程中重复使用相同的建造者。

缺点

  • 如果产品的属性较少,建造者模式可能会导致代码冗余。
  • 增加了系统的类和对象数量。
Mermaid
正在加载图表…

说明:

  1. Item 接口:定义了商品的基本方法,包括 Name()(名称)、Packing()(包装方式)和 Price()(价格)。
  2. Packing 接口:定义了 Pack() 方法,用于返回包装的形式(如 Wrapper 或 Bottle)。
  3. Wrapper 和 Bottle:分别是 Packing 接口的实现类,提供具体的包装方式。
  4. Burger 和 ColdDrink 抽象类:分别是 Item 的具体实现类,其中:
    • Burger 类定义了返回 Wrapper 作为包装方式,Name() 和 Price() 由子类实现。
    • ColdDrink 类定义了返回 Bottle 作为包装方式,Name() 和 Price() 由子类实现。
  5. VegBurger 和 ChickenBurger:分别是 Burger 的具体实现类,实现了 Name() 和 Price() 方法。
  6. Coke 和 Pepsi:分别是 ColdDrink 的具体实现类,实现了 Name() 和 Price() 方法。
  7. Meal 类:用于保存多个 Item(如 VegBurger、Coke 等),并提供 AddItem() 方法添加商品,GetCost() 方法计算总价,ShowItems() 方法展示所有商品的名称、包装和价格。
  8. MealBuilder 类:提供了两种餐点的构建方法:PrepareVegMeal() 和 PrepareNonVegMeal(),分别用于构建素食餐和非素食餐。

类之间的关系:

  • Item 接口由 Burger 和 ColdDrink 抽象类实现。
  • Packing 接口由 Wrapper 和 Bottle 类实现。
  • VegBurger 和 ChickenBurger 类继承自 Burger,而 Coke 和 Pepsi 类继承自 ColdDrink。
  • Meal 类包含多个 Item 对象,并提供方法来展示和计算餐点的总价。
  • MealBuilder 类负责创建具体的 Meal 实例。
c#
public interface Item
{
    public string Name();
    public Packing Packing();
    public float Price();
}
c#
public interface Packing
{
    public string Pack();
}

原型模式(Prototype Pattern)

注意

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。

它允许对象通过克隆的方式来创建副本,而不是通过构造器来实例化。

优点

  • 性能提高
  • 避免构造函数的约束

缺点

  • 配备克隆方法需要全面考虑类的功能,对已有类可能较难实现,特别是处理不支持串行化的间接对象或含有循环结构的引用时。
  • 必须实现 Cloneable 接口。
Mermaid
正在加载图表…
  • Shape (抽象类):所有形状(如 Rectangle、Square、Circle)的基类,包含了 ICloneable 接口的实现,用于对象克隆。

  • Rectangle、Square、Circle:具体的形状类,继承自 Shape 类并实现 Draw() 方法。

  • ShapeCache:一个缓存类,用来存储和克隆不同的形状对象。
c#
public abstract class Shape : ICloneable
{
    private string id;
    protected string type;
    public abstract void Draw();
    public string GetType()
    {
        return type;
    }
    public string GetId()
    {
        return id;
    }
    public void SetId(string id)
    {
        this.id = id;
    }
    public object Clone()
    {
        object clone = null;
        try
        {
            clone = MemberwiseClone();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        return clone;
    }
}

结构型模式(8)

适配器模式(Adapter Pattern)

注意

适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。它通过一个中间件(适配器)将一个类的接口转换成客户期望的另一个接口,使原本不能一起工作的类能够协同工作。

优点

  • 促进了类之间的协同工作,即使它们没有直接的关联。
  • 提高了类的复用性。
  • 增加了类的透明度。
  • 提供了良好的灵活性。

缺点

  • 过度使用适配器可能导致系统结构混乱,难以理解和维护。
  • 在 Java 中,由于只能继承一个类,因此只能适配一个类,且目标类必须是抽象的(C++ 可以多继承,C# 可以用接口来实现多继承)。

结构

适配器模式包含以下几个主要角色:

  • 目标接口(Target):定义客户需要的接口。
  • 适配者类(Adaptee):定义一个已经存在的接口,这个接口需要适配。
  • 适配器类(Adapter):实现目标接口,并通过组合或继承的方式调用适配者类中的方法,从而实现目标接口。
Mermaid
正在加载图表…
  • MediaPlayer 接口:定义了一个播放音频文件的 Play() 方法。

  • AdvancedMediaPlayer 接口:定义了播放 vlc 和 mp4 格式音频文件的方法。

  • VlcPlayer 和 Mp4Player:实现了 AdvancedMediaPlayer 接口,分别可以播放 vlc 和 mp4 格式的文件。

  • MediaAdapter:适配器类,能将 MediaPlayer 接口的请求转换为 AdvancedMediaPlayer 接口的方法调用,从而使得 AudioPlayer 可以播放 vlc 和 mp4 格式的文件。

  • AudioPlayer:客户端类,负责播放 mp3 文件,且通过 MediaAdapter 支持播放 vlc 和 mp4 格式文件。

c#
public interface MediaPlayer
{
    public void Play(string audioType, string fileName);
}
 
public interface AdvancedMediaPlayer
{
    public void playVlc(string fileName);
    public void playMp4(string fileName);
}

桥接模式(Bridge Pattern)

注意

桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。

关键代码

  • 抽象类:定义一个抽象类,作为系统的一部分。
  • 实现类:定义一个或多个实现类,与抽象类通过聚合(而非继承)关联。
Mermaid
正在加载图表…
  • DrawAPI 接口:定义了具体绘制图形的方法(如绘制圆形)。它是实现部分的接口。

  • RedCircle 和 GreenCircle 类:这两个类实现了 DrawAPI 接口,分别提供绘制红色和绿色圆形的具体实现。

  • Shape 抽象类:通过持有一个 DrawAPI 对象,它将绘制的具体实现推迟到子类中,从而实现了绘制的抽象和实现分离。

  • Circle 类:具体的形状类,继承自 Shape,并通过 DrawAPI 来决定如何绘制圆形。

c#
public interface DrawAPI {
    public void DrawCircle(int radius, int x, int y);
}

过滤器模式(Filter Pattern)

注意

过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。

Mermaid
正在加载图表…
  • Person 类:表示一个人的基本信息,包括姓名、性别和婚姻状况。提供了 getter 方法来获取这些信息。

  • Criteria 接口:定义了筛选方法 MeetCriteria(),所有具体的标准类都实现这个接口。

  • CriteriaMale、CriteriaFemale 和 CriteriaSingle 类:这些是具体的标准类,根据性别或婚姻状况来筛选 Person 对象。

  • AndCriteria 和 OrCriteria 类:这两种类通过组合已有的标准(即通过 "与" 或 "或" 逻辑)来定义更复杂的筛选条件。

c#
public class Person {
    private string name;
    private string gender;
    private string maritalStatus;  // 婚姻状况
    public Person(string name, string gender, string maritalStatus) {
        this.name = name;
        this.gender = gender;
        this.maritalStatus = maritalStatus;
    }
    public string GetName() {
        return name;
    }
    public string GetGender() {
        return gender;
    }
    public string GetMaritalStatus() {
        return maritalStatus;
    }
}

组合模式(Composite Pattern)

注意

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

Mermaid
正在加载图表…
Mermaid
正在加载图表…
c#
public class Employee
{
    private string name;
    private string dept;
    private int salary;
    private List<Employee> subordinates;
 
    public Employee(string name, string dept, int salary)
    {
        this.name = name;
        this.dept = dept;
        this.salary = salary;
        this.subordinates = new List<Employee>();
    }
 
    public void Add(Employee emp)
    {
        subordinates.Add(emp);
    }
 
    public void Remove(Employee emp)
    {
        subordinates.Remove(emp);
    }
 
    public List<Employee> GetSubordinates()
    {
        return subordinates;
    }
 
    public string toString()
    {
        return "Name: " + name + ", Department: " + dept + ", Salary: " + salary;
    }
 
}

装饰器模式(Decorator Pattern)

注意

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

Mermaid
正在加载图表…
c#
public interface Shape {
    void Draw();
}

外观模式(Facade Pattern)

注意

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

应用实例

通过外观模式,可以简化对表示层、业务逻辑层和数据访问层的访问。

Mermaid
正在加载图表…
c#
public interface Shape
{
    void Draw();
}

享元模式(Flyweight Pattern)

注意

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

Mermaid
正在加载图表…
c#
public interface Shape
{
    void Draw();
}

代理模式(Proxy Pattern)

注意

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能,这种类型的设计模式属于结构型模式。

代理模式通过引入一个代理对象来控制对原对象的访问。代理对象在客户端和目标对象之间充当中介,负责将客户端的请求转发给目标对象,同时可以在转发请求前后进行额外的处理。

Mermaid
正在加载图表…
c#
public interface Image {
    void Display();
}

行为型模式(12)

责任链模式(Chain of Responsibility Pattern)

注意

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

意图

允许将请求沿着处理者链传递,直到请求被处理为止。每个处理对象(日志记录器)只关注处理自己能够处理的日志级别,无法处理的请求则传递给下一个处理对象。

Mermaid
正在加载图表…
c#
public abstract class AbstractLogger {
    public static int INFO = 1;
    public static int ERROR = 2;
    public static int DEBUG = 3;
    protected int level;
    protected AbstractLogger nextLogger;
    public void SetNextLogger(AbstractLogger nextLogger) {
        this.nextLogger = nextLogger;
    }
    public void LogMessage(int level, string message) {
        if (this.level <= level) {
            Write(message);
        }
        if (nextLogger != null) {
            nextLogger.LogMessage(level, message);
        }
    }
    protected abstract void Write(string message);
}
Mermaid
正在加载图表…

命令模式(Command Pattern)

注意

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。

命令模式将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

Mermaid
正在加载图表…
c#
public interface Order {
    void exeute();
}

解释器模式(Interpreter Pattern)

注意

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。

解释器模式给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

这种模式被用在 SQL 解析、符号处理引擎等。

Mermaid
正在加载图表…
c#
public interface Expression {
    public bool Interpret(string context);
}

迭代器模式(Iterator Pattern)

注意

迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

Mermaid
正在加载图表…
c#
public interface Iterator
{
    public bool HasNext();
    public object Next();
}
public interface Container
{
    public Iterator GetIterator();
}

中介者模式(Mediator Pattern)

注意

中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性,属于行为型模式。

中介者模式定义了一个中介对象来封装一系列对象之间的交互。中介者使各对象之间不需要显式地相互引用,从而使其耦合松散,且可以独立地改变它们之间的交互。

MVC 框架:控制器(C)作为模型(M)和视图(V)的中介者。

Mermaid
正在加载图表…
c#
public class ChatRoom {
    public static void ShowMessage(User user, string message) {
        Console.WriteLine(user.GetName() + ": " + message);
    }
}

备忘录模式(Memento Pattern)

注意

备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象,备忘录模式属于行为型模式。

备忘录模式允许在不破坏封装性的前提下,捕获和恢复对象的内部状态。

应用实例

  • 游戏存档:保存游戏进度,允许玩家加载之前的存档。
  • Windows 中的 Ctrl + Z:实现撤销操作。
Mermaid
正在加载图表…
c#
public class Memento  // 备忘录
{
    private string state;
    public Memento(string state)
    {
        this.state = state;
    }
    public string GetState()
    {
        return state;
    }
}

观察者模式(Observer Pattern)

注意

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

Mermaid
正在加载图表…
c#
public class Subject
{
    private List<Observer> observers = new List<Observer>();
    private int state;
    public int GetState()
    {
        return state;
    }
    public void SetState(int state)
    {
        this.state = state;
        NotifyObservers();
    }
    public void Attach(Observer observer)
    {
        observers.Add(observer);
    }
    public void Detach(Observer observer)
    {
        observers.Remove(observer);
    }
    private void NotifyObservers()
    {
        foreach (Observer observer in observers)
        {
            observer.Update();
        }
    }
}

状态模式(State Pattern)

注意

在状态模式(State Pattern)中,类的行为是基于它的状态改变的,这种类型的设计模式属于行为型模式。

在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

Mermaid
正在加载图表…
c#
public interface State
{
    public void DoAction(Context context);
}

空对象模式(Null Object Pattern)

注意

在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。

在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。

使用一个空对象代替 null 值,这个空对象实现了相同的接口,但对请求不做任何操作或提供默认操作。

Mermaid
正在加载图表…
c#
public abstract class AbstractCustomer {
    protected string name;
    public abstract bool IsNil();
    public abstract string GetName();
}

策略模式(Strategy Pattern)

注意

在策略模式(Strategy Pattern)中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

意图:将每个算法封装起来,使它们可以互换使用。

Mermaid
正在加载图表…
c#
public interface Strategy {
    public int DoOperation(int num1, int num2);
}

模板模式(Template Pattern)

注意

模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

Mermaid
正在加载图表…
c#
public abstract class Game {
    public abstract void Initialize();
    public abstract void StartPlay();
    public abstract void EndPlay();
    public void Play() {
        Initialize();
        StartPlay();
        EndPlay();
    }
}

访问者模式(Visitor Pattern)

注意

在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。

Mermaid
正在加载图表…
c#
public interface ComputerPart {
    public void Accept(ComputerPartVisitor computerPartVisitor);
}