有些设计模式日用而不知,有些设计模式看似概念复杂实则内核简单,还有些设计模式则化繁为简直至少即是多——本文,将在极简形式下,传递出基础设计模式最核心的基本思想,一共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等于s2s1 = 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(ILoggerFactory 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,来实例化ComputerComputer(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()
{// 创建复杂对象,需要进行大量计算,以及外部资源调用,如网络、数据库、认证、审核等等co = new ComplexObject();// 客户端直接复制,没有复杂计算与资源调用c1 = co.Clone();c2 = co.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(ICoffee coffee) => this.coffee = coffee;void Make(){this.coffee.Make();Print("加入牛奶");}
}// 不改变咖啡接口,给咖啡加冰块
class IceDecorator implements ICoffee
{private ICoffee coffee;IceDecorator(ICoffee 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,才会newimage ??= 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){// 客户端,共享重复的元对象,即abcCharacterFactory.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),并计算出j俄国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();// 客户端,不需要检查对象是否nullLoggerFactory.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种基本适应模式,即:正反馈模式、负反馈模式、一致性与非一致性前馈模式——关键词,就是动态性、可塑性与适应性。
事实上,演化是宇宙中唯一的“成功学”——这是终极的编码与模式,而这样的“演化代码”,是“活的”而不是“死的”。
最后,我们需要超越这些设计模式,而不是死记硬套这些设计模式,要看到这些设计模式的适用性与局限性,而不是拿着这些设计模式的“锤子”看什么都是“钉子”——最终就会,从前看它们很高级,现在看它们就那样,未来看它们啥也不是……这才是全新的开始。
欢迎关注我的知乎专栏:「又在写代码」与「闪念与认知」以及知乎账号(可交流沟通,这里不看也不回复)。