代码设计模式:一句话直击内涵与意义、极简代码示例、基础3类27种,以及更多概念与视角

有些设计模式日用而不知,有些设计模式看似概念复杂实则内核简单,还有些设计模式化繁为简直至少即是多——本文,将在极简形式下,传递出基础设计模式最核心的基本思想,一共3类27种,即:创建型模式6种、结构型模式9种、行为型模式12种。

以下示例,是基于C#与Java语法的“伪代码”,并进行了“大量简化”“改变默认”(可能还有别的一些语法),主旨在于表意清晰,从而可以快速地理解回顾——每个设计模式,都给出了直击内涵意义的一句话概括。

最后,还有更多的概念视角

主题目录如下:

  • 创建型模式6种
  • 结构型模式9种
  • 行为型模式12种
  • 设计模式的意义
  • 更多的设计模式
  • 结语

创建型模式6种(Creational Patterns)

这些设计模式处理对象的创建——其特点在于,外部无法直接实例化对象。

1,单例模式(Singleton Pattern)

  • 内涵:只有一个对象实例,可以全局访问。
  • 意义:全局获取,唯一实例的功能与数据。
class Singleton
{
    // 私有限制外部修改
    private static Singleton instance = new();
    // 私有限制new实例化
    private Singleton();
    // 获取全局唯一实例
    Singleton Get() => instance;
}

void Client()
{
    // 客户端,获取的s1等于s2
    s1 = Singleton.Get();
    s2 = Singleton.Get();
}

2,简单工厂模式(Simple Factory Pattern)

  • 内涵:工厂根据不同参数,创建不同实现的接口对象。
  • 意义:隐藏对象配置,集中对象管理,简化对象获取。
// 不同的操作实现不同的计算
interface IOperation : int Do(num1, num2);

// 实现加法操作
class Add implements IOperation : int Do(num1, num2) => num1 + num2;
// 实现减法操作
class Sub implements IOperation : int Do(num1, num2) => num1 - num2;

// 操作工厂根据操作类型,创建操作对象
// 增加新的类型,需要修改此处已有代码
class OperationFactory : static IOperation Create(type) => switch(type)
{
    case '+': 
        return new Add();
    case '-': 
        return new Sub();
    default : 
        throw("不支持的操作类型"); 
}

void Client()
{
    // 客户端计算加法
    OperationFactory.Create('+').Do(1, 2);
    // 客户端计算减法
    OperationFactory.Create('-').Do(5, 3);
}

3,工厂方法模式(Factory Method Pattern)

  • 内涵:接口工厂创建接口对象,具体实现自由增加。
  • 意义:隐藏工厂与对象的配置,可以扩展无需修改。
// 不同记录器,实现不同的日志
interface ILogger : void Log();

class FileLogger    implements ILogger : void Log() => Print("这是文件日志");
class ConsoleLogger implements ILogger : void Log() => Print("这是控制台日志");

// 不同的记录器工厂,创建不同的记录器
interface ILoggerFactory : ILogger Create();

class FileLoggerFactory    implements ILoggerFactory : ILogger Create() => new FileLogger();
class ConsoleLoggerFactory implements ILoggerFactory : ILogger Create() => new ConsoleLogger();

// 扩展工厂与对象的实现,不影响客户端
ILogger CreateBy(loggerFactory) => loggerFactory.Create();

void Client()
{
    // 客户端创建,文件日志
    CreateBy(new FileLoggerFactory())   .Log();
    // 客户端创建,控制台日志
    CreateBy(new ConsoleLoggerFactory()).Log();
}

4,抽象工厂模式(Abstract Factory Pattern)

  • 内涵:接口工厂创建一组接口对象,具体实现自由增加。
  • 意义:隐藏对象集合的创建复杂性,简化对象集合调用。
// 不同系统的按钮,实现不同的绘制
interface IButton : void Draw();

class WinButton implements IButton : void Draw() => Print("Win Button");
class MacButton implements IButton : void Draw() => Print("Mac Button");

// 不同系统的文本,实现不同的绘制
interface IText : void Draw();

class WinText implements IText : void Draw() => Print("Win Text");
class MacText implements IText : void Draw() => Print("Mac Text");

// 不同系统的图形界面,实现不同的绘制
interface IUIFactory : IButton CreateButton(), IText CreateText();

class WinFactory implements IUIFactory 
{
    IButton CreateButton() => new WinButton();
    IText   CreateText  () => new WinText  ();
}

class MacFactory implements IUIFactory 
{
    IButton CreateButton() => new MacButton();
    IText   CreateText  () => new MacText  ();
}

void Client()
{
    // 客户端根据系统,选择对应工厂
    IUIFactory uiFactory;

    if (IsWin()) 
    {
        uiFactory = new WinFactory();
    } 
    else if (IsMac()) 
    {
        uiFactory = new MacFactory();       
    }
    else 
    {
        throw("不支持的系统");
    }
        
    // 客户端使用工厂,创建相关对象集合,实现相关功能集合
    uiFactory.CreateButton().Draw();
    uiFactory.CreateText  ().Draw();
}

5,建造者模式(Builder Pattern)

  • 内涵:复杂对象分解成多个部分,每个部分独立构建。
  • 意义:降低复杂对象创建难度,可自由替换某个部分。
class Computer 
{
    string cpu;
    string gpu;
    string ram;
    string hdd;

    // 只能通过Builder,来实例化Computer
    Computer(Builder builder);
}

class Builder
{
    private Computer computer;

    // 创建内部Computer实例
    Builder() => this.computer = new Computer(this);

    Builder BuildCPU(cpu) => this.computer.cpu = cpu;
    Builder BuildGPU(gpu) => this.computer.gpu = gpu;
    Builder BuildRAM(ram) => this.computer.ram = ram;
    Builder BuildHDD(hdd) => this.computer.hdd = hdd;

    Computer GetComputer() => this.computer;
}

void Client()
{
    // 客户端可以自由替换Computer的某个部分,也可以放到不同的地方去构建
    computer = new Builder().BuildCPU("cpu")
                            .BuildGPU("gpu")
                            .BuildRAM("ram")
                            .BuildHDD("hdd")
                            .GetComputer();
}

6,原型模式(Prototype Pattern)

  • 内涵:通过复制而不是构造,来创建对象。
  • 意义:提高对象创建性能,节省过程资源。
// 不同对象,实现不同的克隆
interface IPrototype : object Clone();

class ComplexObject implements IPrototype : object Clone() => this.DeepCopy();

void Client()
{
    // 创建复杂对象,需要进行大量计算,以及外部资源调用,如网络、数据库、认证、审核等等
    complexObject = new ComplexObject();
    // 客户端直接复制,没有复杂计算与资源调用
    co1           = complexObject.Clone();
    co2           = complexObject.Clone();
}

结构型模式9种(Structural Patterns)

这些设计模式处理对象的组合——其特点在于,将旧对象转换成新对象。

1,适配器模式(Adapter Pattern)、包装器模式(Wrapper Pattern)

  • 内涵:将一个对象转换成,所需要的对象。
  • 意义:使得不同系统,可以相互适配兼容。
// 目标接口
interface INewTarget : void NewRequest();

class OldTarget : void OldRequest() => Print("旧对象的旧请求");

// 适配器让旧对象,可以实现新对象的接口
class Adapter implements INewTarget
{
    OldTarget oldTarget;
    // 获取需要适配的旧对象
    Adapter(oldTarget) => this.oldTarget = oldTarget;
    // 用旧对象实现,新对象的接口
    void NewRequest() => this.oldTarget.OldRequest();
}

// 只接受新对象的方法
void OnlyNeedNewTarget(INewTarget newTarget) => newTarget.NewRequest();

void Client()
{
    oldTarget = new OldTarget();
    // 客户端通过适配器,将旧对象当成新对象使用
    OnlyNeedNewTarget(new Adapter(oldTarget));
}

2,装饰器模式(Decorator Pattern)

  • 内涵:基于对象实例,添加对象接口的功能。
  • 意义:通过传递对象,来组合功能逐步增强。
// 不同的咖啡,不同的制作
interface ICoffee : void Make();

class Coffee implements ICoffee : void Make() => Print("一杯咖啡");

// 不改变咖啡接口,给咖啡加牛奶
class MilkDecorator implements ICoffee
{
    private ICoffee coffee;

    MilkDecorator(coffee) => this.coffee = coffee;

    void Make()
    {
        this.coffee.Make();
        Print("加入牛奶");
    }
}

// 不改变咖啡接口,给咖啡加冰块
class IceDecorator implements ICoffee
{
    private ICoffee coffee;

    IceDecorator(coffee) => this.coffee = coffee;

    void Make()
    {
        this.coffee.Make();
        Print("加入冰块");
    }
}

void Client()
{
    coffee = new Coffee();
    // 客户端制作一杯咖啡
    coffee.Make();
    
    milkCoffee = new MilkDecorator(coffee);
    // 客户端制作一杯咖啡 + 牛奶
    milkCoffee.Make();

    iceCoffee = new IceDecorator(coffee);
    // 客户端制作一杯咖啡 + 冰块
    iceCoffee.Make();
    
    // 客户端制作一杯咖啡 + 牛奶 + 冰块
    new IceDecorator(milkCoffee).Make();
}

注意,与继承相比,装饰器避免了,暴露父类的复杂细节,以及获得父类的无用结构。

3,代理模式(Proxy Pattern)

  • 内涵:代替原对象处理访问,并施加额外控制。
  • 意义:代理不改变功能,只是控制功能的使用。
class Image
{
    // 实例化图片的时候去加载
    Image()        => Print("加载图片");
    void Display() => Print("显示图片");
}

class ImageProxy
{
    private Image image;

    void Display()
    {
        // 只有image为null,才会new
        image ??= new Image();
        image.Display();
    }
}

void Client()
{
    // 客户端实例化图片代理,此时没有加载图片
    image = new ImageProxy();
    // 第一次显示时,才会延迟加载图片
    image.Display(); 
    // 第二次显示,不再加载图片
    image.Display(); 
}

注意,与装饰器相比,代理不会增强功能,只是控制功能的使用,如权限、时机、统计、日志、路由等等。

4,外观模式(Facade Pattern)、门面模式

  • 内涵:封装复杂功能,提供简化的使用方式。
  • 意义:隐藏系统的复杂性,简单化功能调用。
class AudioLoader  : void LoadAudio  () => Print(“载入音频”);
class AudioDecoder : void DecodeAudio() => Print(“解码音频”);
class AudioPlayer  : void PlayAudio  () => Print(“播放音频”); 

class AudioFacade
{
    private AudioLoader  loader;
    private AudioDecoder decoder;
    private AudioPlayer  player;

    AudioFacade(loader, decoder, player) => 
    (this.loader, this.decoder, this.player) = (loader, decoder, player);
    
    // 外观对象提供简化播放调用
    void Play() 
    {
        this.loader .LoadAudio  ();
        this.decoder.DecodeAudio();
        this.player .PlayAudio  ();
    }
}

void Client()
{
    loader  = new AudioLoader ();
    decoder = new AudioDecoder();
    player  = new AudioPlayer ();

    facade  = new AudioFacade(loader, decoder, player);
    // 客户端使用外观对象,简化音频播放,隐藏播放细节
    facade.Play();
}

5,桥接模式(Bridge Pattern)

  • 内涵:通过接口,来组合不同的功能。
  • 意义:接口自由组合,实现自由替换。
// 不同颜色,实现不同上色 
interface IColor : void ApplyColor();

class Red   implements IColor : void ApplyColor() => Print("表面喷红色");
class Green implements IColor : void ApplyColor() => Print("表面喷绿色");

abstract class Shape
{
    protected IColor color;
    Shape(color) => this.color = color;

    abstract void Draw();
}

class Circle inherits Shape
{
    override void Draw()
    {
        Print("绘制圆形");
        this.color.ApplyColor();
    }
}

class Rect inherits Shape
{
    override void Draw()
    {
        Print("绘制矩形");
        this.color.ApplyColor();
    }
}

void Client()
{
    // 客户端,绘制红色圆形
    new Circle(new Red  ()).Draw();
    // 客户端,绘制绿色矩形
    new Rect  (new Green()).Draw();
}

注意:

  • 与抽象工厂相比,桥接是使用接口实现的功能,抽象工厂是创建实现接口的对象。
  • 与装饰器相比,桥接是平行组合接口实现功能,装饰器是嵌套组合接口增强功能。

6,组合模式(Composite Pattern)

  • 内涵:将对象组成树形结构,每个节点含有一个节点集合。
  • 意义:统一整体与部分的行为接口,可递归处理每个节点。
// 不同节点,绘制自己
interface INode : void Paint();

class Leaf implements INode : void Paint() => Print("这是树叶");
class Root implements INode
{
    private List<INode> nodes = new();

    void Add(node) => this.nodes.Add(node);

    void Paint()
    {
         Print("这是树根,以及子节点");
         foreach (node in this.nodes) node.Paint();
    }
}

void Client()
{
    root1 = new Root();
    root1.Add(new Leaf());
    
    root2 = new Root();
    root2.Add(new Leaf());
    
    // 客户端,root可以添加leaf和root(自己),实际中可以用root充当leaf会更统一
    root2.Add(root1);
    // 客户端,leaf(部分)和root(整体)有相同的行为,某个root也可以看成某个部分
    root2.Paint();
}

7,对象池模式(Object Pool Pattern)

  • 内涵:缓存对象,重用对象的空间与功能。
  • 意义:减少内存的使用与操作,提高性能。
// 可池化对象
class Poolable
{
    // 出池子前,要初始化
    Poolable Init () => Print("初始化");
    // 进池子前,要重置(释放资源或防止误用)
    Poolable Reset() => Print("重置");
}

class Pool
{
    // 缓存使用过的对象
    private Stack cache = new();
    
    // 对象池不空,就返回缓存的对象,否则创建一个
    public Poolable Get() => cache.Count > 0 ? pool.Pop().Init() : new Poolable().Init();
    
    // 对象用完放回池子,缓存起来
    public void Return(poolable) => cache.Push(poolable.Reset());
}

void Client()
{
    pool      = new Pool();
    poolable1 = pool.Get();
    poolable2 = pool.Get();

    pool.Return(poolable1);
    // 客户端,从对象池获取缓存的对象
    poolable3 = pool.Get();
}

8,享元模式(Flyweight Pattern)

  • 内涵:共享对象,共用对象的数据与状态。
  • 意义:减少内存的浪费与膨胀,提高性能。
class Character
{
     private char c;
     Character(c) => this.c = c;
     void Draw()  => Print("自动排版绘制字符");
}

class CharacterFactory
{
    private static Dictionary<c, Character> cache = new();

    static Character Get(c)
    {
        if (cache.ContainsKey(c) == false)
        {
            cache[c] = new Character(c);
        }

        return cache[c];
    }
}

void Client()
{
    txt = "aabbccabc";

    foreach (c in txt)
    {
        // 客户端,共享重复的元对象,即abc
        CharacterFactory.Get(c).Draw();
    }
}

注意,与对象池相比,享元是对象共用,即一个对象用在多处(内存共用),对象池是对象重用,即一个对象销毁再建(内存重用)。

9,过滤器模式(Filter Pattern)、标准模式(Criteria Pattern)

  • 内涵:按照某些规则,过滤符合条件的对象集合。
  • 意义:不需要了解实现细节,组合使用过滤规则。
// 不同的标准,过滤不同的人
interface ICriteria : List<Person> Filter(persons);

class Person 
{ 
    string name;
    int    age;
}

class NameCriteria implements ICriteria
{
    private string name;
    NameCriteria(name) => this.name = name;

    List<Person> Filter(persons) => persons.Where(p => p.Name == name);
}

class AgeCriteria implements ICriteria
{
    private int age;
    AgeCriteria(age) => this.age = age;

    List<Person> Filter(persons) => persons.Where(p => p.Age == age);
}

class AndCriteria implements ICriteria
{
    private ICriteria criteria1;
    private ICriteria criteria2;

    AndCriteria(criteria1, criteria2) => 
    (this.criteria1, this.criteria2) = (criteria1, criteria2);

    List<Person> Filter(persons) => criteria2.Filter(criteria1.Filter(persons));
}

void Client()
{
    nameCriteria = new NameCriteria("瑞克");    
    ageCriteria  = new AgeCriteria (66);
    // 客户端,过滤出名叫瑞克且66岁的人
    persons = new AndCriteria(nameCriteria, ageCriteria).Filter(personList);
}

行为型模式12种(Behavioral atterns

这些设计模式处理对象的交互——其特点在于,将改变都封装到独立的对象。

1,策略模式(Strategy Pattern)

  • 内涵:封装复杂算法,实现对象行为接口。
  • 意义:自由扩展对象行为,无需修改对象。
// 不同的策略,不同的行为
interface IStrategy : void Execute();

class KillPlan     implements IStrategy : void Execute() => Print("伐谋");
class KillAlliance implements IStrategy : void Execute() => Print("伐交");
class KillArmy     implements IStrategy : void Execute() => Print("伐兵");

class Machine
{
    private IStrategy strategy;
    Machine(strategy)  => this.strategy = strategy;

    void Set(strategy) => this.strategy = strategy;
    void Execute()     => this.strategy.Execute();
}

void Client()
{
    Machine = new Machine(new KillPlan());
    // 客户端,执行"伐谋"
    machine.Execute();  
   
    machine.Set(new KillAlliance());
    // 客户端,执行"伐交"
    machine.Execute(); 
 
    machine.Set(new KillArmy());
    // 客户端,执行"伐兵"
    machine.Execute();  
}

注意:

  • 与抽象工厂相比,策略是切换对象行为,抽象工厂是创建不同功能的对象。
  • 与桥接相比,策略是对象行为单独变化,桥接是对象与功能两者独立变化。

2,模板方法模式(Template Method Pattern)

  • 内涵:固定算法的结构与流程,由具体对象实现细节。
  • 意义:共享通用的流程与步骤,自定义实现特殊步骤。
abstract class TeaMaker
{
    // 模板方法,定义泡茶流程
    void MakeTea()
    {
        BoilWater();
        BrewTea  ();
        PourInto ();

        Print("茶已做好");
    }

    // 抽象方法,留给子类实现
    abstract void BoilWater();
    abstract void BrewTea  ();
    abstract void PourInto ();
}

// 制作绿茶
class GreenTea inherits TeaMaker
{
    override void BoilWater() => Print("烧85度纯净水");
    override void BrewTea  () => Print("泡3分钟");
    override void PourInto () => Print("倒入玻璃杯");
}

// 制作红茶
class BlackTea inherits TeaMaker
{
    override void BoilWater() => Print("烧100度纯净水");
    override void BrewTea  () => Print("泡5分钟");
    override void PourInto () => Print("倒入陶瓷杯");
}

void Client()
{
    // 客户端,制作绿茶
    new GreenTea().MakeTea();
    // 客户端,制作红茶
    new BlackTea().MakeTea();
}

3,观察者模式(Observer Pattern)、发布订阅模式(Publish Subscribe Pattern)

  • 内涵:对象状态改变,通知注册的观察者处理。
  • 意义:一对多关系,实现自动化低耦合的协作。
// 观察者,可以收到更新通知
interface IObserver : void Update(message);

class Watch implements IObserver : void Update(message) => Print("更新信息:{message}");
class Phone implements IObserver : void Update(message) => Print("更新信息:{message}");

// 可被观察者,可以发送通知给观察者
interface IObservable : void Add(observer), void Notify(message);

class CarSystem implements IObservable
{
    private List<IObserver> observerList = new();
    
    // 添加观察者
    void Add(observer)   => this.observerList.Add(oberver);
    // 通知观察者
    void Notify(message) => foreach (observer in this.observerList) observer.Update(message);
}

void Client()
{
    CarSystem = new CarSystem();
    CarSystem.Add(new Watch());
    CarSystem.Add(new Phone());
    // 客户端,被观察者(主题)通知观察者(订阅),状态的改变
    CarSystem.Notify("有人正在试图打开车门");
}

4,状态模式(State Pattern)

  • 内涵:封装对象行为到状态对象,切换状态对象改变对象行为。
  • 意义:解耦对象与状态行为,简化对象状态行为的切换与扩展。
interface IState : void Handle(animal);

class Fight  implements IState : void Handle(animal) => Print("战斗状态");
class Flight implements IState : void Handle(animal) => Print("逃跑状态");
class Freeze implements IState : void Handle(animal) => Print("僵住状态"); 
class Idle   implements IState : void Handle(animal) => Print("空闲状态"); 
 
class Animal
{
    private IState state;
    Animal(state) => this.SetState(state);
    
    void SetState(state)
    {
        this.state = state;
        this.state.Handle(this);
    }
}

void Client()
{
    // 客户端,空闲状态的动物,遇到不同情况,切换不同状态
    animal = new Animal(new Idle());

    if (Has("情敌"))
    {
        animal.SetState(new Fight());
    } 
    else if (Has("天敌"))
    {
        animal.SetState(new Flight()); 
    }
    else if (Has("群敌"))
    {
        animal.SetState(new Freeze()); 
    }
}

5,命令模式(Command Pattern)

  • 内涵:将请求封装成命令对象,发送给调用者处理。
  • 意义:实现命令的排序、队列、并行、延迟、撤销。
// 不同的命令,不同的执行
interface ICommand : void Execute();

// 开灯命令
class LightOn implements ICommand
{
    LightOn(light) => this.light = light;
    void Execute() => this.light.TurnOn();
}

// 关灯命令
class LightOff implements ICommand
{
    LightOff(light) => this.light = light;
    void Execute()  => this.light.TurnOff();
}

// 命令的执行者
class Light
{
    void TurnOn () => Print("开灯");
    void TurnOff() => Print("关灯");
}

// 命令调用者
class UI
{
    private ICommand command;

    void SetCommand(command) => this.command = command;
    void Click()             => command?.Execute();
}

void Client()
{
    // 命令执行者
    light    = new Light   ();
    // 请求绑定执行者,形成命令
    lightOn  = new LightOn (light);
    lightOff = new LightOff(light);
    // 命令调用者
    ui       = new UI();
        
    ui.SetCommand(lightOn);
    // 客户端,调用开灯命令
    ui.Click();  

    ui.SetCommand(lightOff);
    // 客户端,调用关灯命令
    ui.Click(); 
}

注意,与策略相比,命令封装的是请求与执行,策略封装的是行为算法,前者需求明确直接选择,后者需要匹配问题灵活选择。

6,责任链模式(Chain of Responsibility Pattern)

  • 内涵:对象处理不了请求,就转发给另一个对象。
  • 意义:解耦请求与处理,将复杂请求按责任分割。
class Order 
{
    private double amount;
    Order(amount) => this.amount = amount;
    GetAmount()   => this.amount;
}

// 不同的订单,不同的处理方式
abstract class OrderHandler 
{
    private OrderHandler next;
    // 处理不了,转发到下一个
    void SetNext(next) => this.next = next;

    abstract void Handle(order);
} 

// 普通员工处理订单
class Junior inherits OrderHandler
{
    override void Handle(order)
    {   
        order.GetAmount() <= 500 ? Print("普通员工处理订单") : this.next.Handle(order);
    }
}

// 高级员工处理订单
class Senior inherits OrderHandler
{
    override void Handle(order)
    {
        order.GetAmount() <= 2000 ? Print("高级员工处理订单") : this.next.Handle(order);
    }
}

// 经理员工处理订单
class Manager inherits OrderHandler
{
    override void Handle(order)
    {
        order.GetAmount() <= 10000 ? Print("经理员工处理订单") : this.next.Handle(order);
    }
}

void Client()
{
    junior  = new Junior ();
    senior  = new Senior ();
    manager = new Manager();

    junior.SetNext(senior );
    senior.SetNext(manager);

    order1 = new Order(300 );
    order2 = new Order(1500);
    order3 = new Order(3000);  
    
    // 客户端,处理不了的订单会转发
    junior.Handle(order1);
    junior.Handle(order2);
    junior.Handle(order3);
}

7,中介者模式(Mediator Pattern)

  • 内涵:使用一个中转平台,来协调多个对象之间的交互。
  • 意义:解耦对象的交互依赖,集中管理对象的交互逻辑。
// 中介者,可以注册用户,并向用户发送信息
interface IMediator : void Register(user), void Send(user, message);

// 聊天室,充当用户的中介者
class ChatRoom implements IMediator
{
    private List<User> userList = new();

    void Register(user)
    {
        userList.Add(user);
        // 注册用户,持有中介者
        user.SetMediator(this);
    }

    void Send(user, message)
    {
        foreach (one in userList)
        {  
            if (one != user)
            {
                // 不是发送者的用户,会收到信息
                one.Receive(message);
            }
        }
    }
}

class User
{
    private   string    name;
    protected IMediator mediator;

    User(name)                 => this.name     = name;
    void SetMediator(mediator) => this.mediator = mediator;
    // 用户将自己与信息,发给中介者,来转发信息
    void Send(message)         => this.mediator.Send(this, message);
    // 用户收到,中介者发来的信息
    void Receive(message)      => Print("{this.name}, 接收到信息,{message}");
}

void Client()
{
    chatRoom = new ChatRoom(); 
    laoWang  = new user("老王");
    xiaoLi   = new user("小李");

    chatRoom.Register(laoWang);
    chatRoom.Register(xiaoLi);

    laoWang.Send("来自老王向大家的问候");
    xiaoLi .Send("来自小李向大家的问候");
}

8,迭代器模式(Iterator Pattern)

  • 内涵:实现遍历接口,顺序访问集合对象的每个元素。
  • 意义:统一遍历形式,隐藏不同集合对象的内部结构。
interface IIterator : bool HasNext(), int Next();

class Lottery
{
    private int[] nums = { 1, 2, 3, 4, 5, 6, 7 };

    // 返回彩票迭代器 
    IIterator CreateIterator() => new Iterator(nums);

    // 实现彩票迭代器
    private class Iterator implements IIterator
    {
        private int   index = -1;
        private int[] nums;

        Iterator(nums) => this.nums = nums;

        bool HasNext() => index < this.nums.Count;
        int  Next   () => this.nums[++index];
    }
}

void Client()
{
    lottery  = new Lottery();
    iterator = lottery.CreateIterator();

    // 客户端,遍历彩票号码
    while (iterator.HasNext())
    {
        Print(iterator.Next());
    }
}

9,访问者模式(Visitor Pattern)

  • 内涵:将对象的行为算法,转移到访问者中去实现。
  • 意义:分离对象的数据与行为,便于实现不同行为。
// 智能电灯、智能插座,可以被不同的访问者操控
interface IVisitor
{
    void Visit(smartLight);
    void Visit(smartPlug);
}

// 智能产品,可以被访问者操控
interface ISmart : void Accept(visitor);

class SmartLight implements ISmart
{
    // 智能电灯,接受访问者的操控
    void Accept(visitor) => visitor.Visit(this);
    void GetInfo()       => Print("这是智能电灯");
}

class SmartPlug implements ISmart
{
    // 智能插座,接受访问者的操控
    void Accept(visitor) => visitor.Visit(this);
    void GetInfo()       => Print("这是智能插座");
}

// 智能家,可以操控智能产品
class SmartHome implements IVisitor
{
    // 必须要,智能电灯接受,才能访问
    void Visit(smartLight) => smartLight.GetInfo();
    // 必须要,智能插座接受,才能访问
    void Visit(smartPlug)  => smartPlug .GetInfo();
}

// 家智能访问者,可以操控智能产品
class HomeAI implements IVisitor
{
    // 必须要,智能电灯接受,才能访问
    void Visit(smartLight) => Print("人工智能接管电灯");
    // 必须要,智能插座接受,才能访问
    void Visit(smartPlug)  => Print("人工智能接管插座");
}

void Client()
{
    smartLight = new SmartLight();
    smartPlug  = new SmartPlug ();

    // 客户端,通过智能家,控制智能产品
    smartHome = new SmartHome();
    smartLight.Accept(smartHome);
    smartPlug .Accept(smartHome);

    // 客户端,通过家智能,控制智能产品
    homeAI = new HomeAI();
    smartLight.Accept(homeAI);
    smartPlug .Accept(homeAI);
}

注意:

  • 与策略相比,访问者实现不同行为,依赖于对象的数据结构,策略实现不同行为,独立于对象的数据结构。
  • 与命令相比,访问者是对象选择自身的行为,行为与对象有关,命令是对象选择请求的执行,执行与对象无关。

10,解释器模式(Interpreter Pattern)

  • 内涵:将语法抽象为表达式,嵌套组合表达式并解释出结果。
  • 意义:分离语法规则与解释逻辑,分解复杂规则为简单逻辑。
// 可以解释的表达式,参数是上下文信息
interface IExpression : int Interpret(ctxDict);

// 字符表达式(终结符表达式)
class StrExpression implements IExpression
{
    private string str;
    StrExpression(str) => this.str = str;
    // 通过上下文,将字符解释为数字
    int Interpret(ctxDict) => ctxDict[str];
}

// 乘法表达式(非终结符表达式)
class MulExpression implements IExpression
{
    private IExpression left;
    private IExpression right;

    MulExpression(left, right) => this.left = left, this.right = right;
    
    // 通过上下文,将左右表达式,解释为乘法
    int Interpret(ctxDict) => left.Interpret(ctxDict) * right.Interpret(ctxDict);
}

// 除法表达式(非终结符表达式)
class DivExpression implements IExpression
{
    private IExpression left;
    private IExpression right;

    DivExpression(left, right) => this.left = left, this.right = right;
    
    // 通过上下文,将左右表达式,解释为除法
    int Interpret(ctxDict) => left.Interpret(ctxDict) / right.Interpret(ctxDict);
}

void Client()
{
    // 解释器的上下文信息
    ctxDict = new Dictionary<string, int>
    {
        ["a"] = 11,
        ["b"] = 22,
        ["c"] = 33,
    };

    // 表达式树(a * b / c)
    expression = new DivExpression
                 (
                     new MulExpression
                     (
                         new StrExpression("a"),
                         new StrExpression("b")
                     ),
                     new StrExpression("c")
                 );

    // 客户端,根据上下文,解释表达式为(11 * 22 / 33),并计算出结果
    result = expression.Interpret(ctxDict);
}

11,备忘录模式(Memento Pattern)

  • 内涵:备份与恢复对象的状态。
  • 意义:实现撤销与回滚的操作。
// 备忘录对象,可以保存状态
class Memento
{
    private string state;
    // 备忘状态
    Memento(state)    => this.state = state;
    // 获取状态
    string GetState() => this.state;
}

// 存储备忘录对象
class Taker
{
    private static Dictionary<string, Memento> mtDict = new();
    // 保存备忘对象
    AddMemento(name, memento) => this.mtDict[name] = memento;
    // 获取备忘对象
    GetMemento(name)          => this.mtDict[name];
}

// 内存状态可以备份与恢复
class Memory
{
    private string state;

    SetState    (state)   => this.state = state;
    // 备份内存状态,到备忘录对象
    BackupState ()        => new Memento(state);
    // 恢复内存状态,从备忘录对象
    RestoreState(memento) =>  this.state = memento.GetState();
}

void Client()
{
    memory = new Memory();
    taker  = new Taker();

    memory.SetState("## 要死不活状态 ##");
    // 备忘die状态
    taker.AddMemento("die", memory.BackupState());

    memory.SetState("hell", "## 生不如死状态 ##");
    // 备忘hell状态
    taker.AddMemento(memory.BackupState());
    
    // 客户端,决定还是回到die状态
    memory.RestoreState(taker.GetMemento("die"));
}

12,空对象模式(Null Object Pattern)

  • 内涵:用空对象,代替空值或无法操作。
  • 意义:避免检查,无效或无意义的结果。
interface ILogger : void Log(message);

class RealLogger implements ILogger : void Log(message) => Print("记录日志:{message}");
class NullLogger implements ILogger : void Log(message) => Print("没有记录器");

class LoggerFactory
{
    static ILogger Get(type)
    {
        if (type == "File" || type == "Console")
        {
            return new RealLogger();
        }
        else
        {
            return new NullLogger();
        }
    }
}

void Client()
{
    LoggerFactory.Get("File").log();
    // 客户端,不需要检查对象是否null
    LoggerFactory.Get("FFFF").log(); 
}

设计模式的意义

主要在于两个层面:一个是形式上具有通用性复用性,一个是功能上具有抽象性封装性,并且都是前者(抽象通用)支撑了后者(封装复用)。

更进一步,抽象性可以保证封装性,而达成这两者,就可以阻断或减少耦合性,即实现解耦——因为,紧密复杂的耦合性,总是发生在抽象不本质封装不严密的时候(这个视角可以迁移到物理学上的相互作用)。

但,为什么要追求解耦呢?

因为人脑的算力有限,需要降低理解难度(看不懂步骤)、认知负荷(搞不清步骤)与心智负担(记不住步骤),也就是降低系统复杂性,方能有效处理代码结构的逻辑关系。

那么,其效用就在于——获得代码系统的稳定性健壮性效率性可扩展性可维护性可替换性

所以,最佳的设计模式,是将可以系统、模块、功能等,彻底抽象封装成一个“黑盒”——可以“闭眼调用”,就像我们使用大脑,并不需要了解脑科学的神经运作原理一样,这是演化算法的抽象封装,或说是演化的设计模式

更多的设计模式

以上展示的设计模式,几乎代表了基础常用的全部,在此之上可以进行——组合搭配、细化改进与丰富增强,甚至创新创造,从而应对不同的业务模型,比如以下7种:

1,基于单例模式、工厂模式、代理模式——实现“延迟初始化模式”(Lazy initialization Pattern),即:初次使用时初始化。

2,基于单例模式 + 工厂模式——实现“多例模式”(Multiton Pattern),即:工厂产生多个单例。

3,基于装饰器模式——实现“资源自动化模式”(Resource Acquisition is Initialization,RAII),即:资源自动初始化与释放。

4,基于责任链模式——实现“委托模式”(Delegation Pattern),即:实际功能委托给其它对象处理。

5,基于责任链模式 + 外观模式——实现“双继承模式”(Twin Pattern),即:两个子对象组合在一起,就像继承了两个父类(外观提供),而一个对象没有的功能,就转发给另一个对象处理(责任链提供)。

6,基于桥接模式 + 外观模式——实现“服务模式”(Servant Pattern),即:为接口对象实现统一的新功能(桥接提供),传入接口对象,就可以获得新功能的服务(外观提供),而不必每个对象各自实现。

7,基于解释器模式 + 过滤器模式——实现“规范模式”(Specification Pattern),即:根据规则组合,进行逻辑判断(解释器提供),实现过滤查询(过滤器提供)。

还有一些过于“轻量”,一看就了解,如:

  • “流畅接口模式”(Fluent Interface Pattern)——就是“链式调用”。
  • “标记接口模式”(Marker Interface Pattern)——就是“元数据声明”或“空接口声明”。
  • “模块化模式”(Module Pattern )——就是“代码命名空间”。

更多模式可以参看:维基百科Software Design Pattern,很多基础模式来自经典书籍:维基百科《GoF Design Patterns》——注意,本文示例总结,并未参考这两处内容,但这两个链接提供了丰富的相关资料,可作为补充查阅。

结语

事实上,一旦熟悉掌握融会贯通,就会发现设计模式之于编程,是无法绕过的无处不在——除非,机器生成、尽情冗余、无人阅读。

然而,代码设计模式,只是对领域与业务的抽象建模,显然不同的领域与业务会千差万别,尽管基础模式具有一定的通用性,但也不可能全面覆盖,所以随着环境情况的变化实践,一定会有适应不同需求的设计模式,不断被发明应用

那么,在基本层面与底层方向上,不同的视角抽象,也会有不同的理解建模——所有的模型都是错的,只是有些是有用的——因此,已有的所有设计模式,也并非是唯一解最优解,而只是某个解某种解

至于,是否存在“万金油模式”——从抽象封装角度来看,是几乎没有的,但从演化角度来看,是可能存在的,即基于迭代试错的“最优解”

从某种角度说,人脑设计基于抽象封装——是静态的一事一议,自然演化基于迭代试错——是动态的适应塑造,而后者的动态性就在于贯穿生命体,从微观到宏观的3种基本适应模式,即:正反馈模式、负反馈模式、一致性与非一致性前馈模式——关键词,就是动态性可塑性适应性

事实上,演化是宇宙中唯一的“成功学”——这是终极的编码模式,而这样的“演化代码”,是“活的”而不是“死的”

最后,我们需要超越这些设计模式,而不是死记硬套这些设计模式,要看到这些设计模式的适用性与局限性,而不是拿着这些设计模式的“锤子”看什么都是“钉子”——最终就会,从前看它们很高级,现在看它们就那样,未来看它们啥也不是……这才是全新的开始。

欢迎关注我的知乎专栏:「又在写代码」「闪念与认知」以及知乎账号(可交流沟通,这里不看也不回复)。