有些设计模式日用而不知,有些设计模式看似概念复杂实则内核简单,还有些设计模式则化繁为简直至少即是多——本文,将在极简形式下,传递出基础设计模式最核心的基本思想,一共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种基本适应模式,即:正反馈模式、负反馈模式、一致性与非一致性前馈模式——关键词,就是动态性、可塑性与适应性。
事实上,演化是宇宙中唯一的“成功学”——这是终极的编码与模式,而这样的“演化代码”,是“活的”而不是“死的”。
最后,我们需要超越这些设计模式,而不是死记硬套这些设计模式,要看到这些设计模式的适用性与局限性,而不是拿着这些设计模式的“锤子”看什么都是“钉子”——最终就会,从前看它们很高级,现在看它们就那样,未来看它们啥也不是……这才是全新的开始。