设计模式简评

103 阅读6分钟

创建型模式

工厂方法(Factory Method)

用于创建同一接口的不同实现类。例如 SLF4J 的 LoggerFactory.getLogger(),其返回的具体 Logger 实例取决于实际使用的日志框架实现。这种动态创建能力是普通构造函数无法实现的。

抽象工厂(Abstract Factory)

用于创建一组存在关联关系的接口实现类。该模式在实际开发中使用频率较低,适用于需要保证多组相关对象协同工作的场景。

建造者(Builder)

适用于参数众多且多数参数可选的复杂对象构造。通过链式调用逐步构建对象,显著提升代码可读性。实践中可直接使用 Lombok 的 @Builder@SuperBuilder 注解自动生成建造者代码。

原型(Prototype)

通过复制现有实例来创建新对象,本质上是 Java 原生 Object.clone() 方法的模式化应用。需注意实现深拷贝时需特殊处理引用类型字段。

单例(Singleton)

确保全局唯一实例的模式。例如数据库 client。推荐通过依赖注入框架(如 Spring 的 @Singleton)实现,既保证单例特性又便于单元测试时注入 Mock 对象。

结构型模式

适配器(Adapter)

解决接口不兼容问题的桥梁模式。对于接口不兼容的对象,通过把一个对象包装为另一个接口,使其能够相互合作。典型如电源转接头,将外国电器插头适配到本国插座。代码中常见于整合遗留系统或第三方库时进行接口转换。

组合(Composite)

用于实现复合数据结构。复合的意思是整体可以被组装成更大的整体,从而形成一棵树。比如,一个加法表达式可以被视为一个整体与其它表达式组成更大的表达式。具体实现时,定义统一组件接口(Expr),定义叶子节点(IntExpr)和复合节点(PlusExpr)。通过递归组合可构造任意复杂度的表达式树。

装饰器(Decorator)

通过封装一个对象,为原对象绑定新的行为。如 Java 的 BufferedInputStream 为输入流添加缓冲能力。装饰后的类与原类具有同样的接口。

外观(Facade)

为复杂系统提供更简单更易于使用的接口。SLF4J 正是日志系统的门面典范,隐藏了底层 Log4j、Logback 等实现差异,提供统一 API。

享元(Flyweight)

通过共享多个对象所共有的相同状态,降低内存占用。例如一个游戏场景里的大量经验球,它们的形状、颜色都是一样的,所不一样的只是位置和速度,因此所有经验球可以共享形状和颜色的数据。Java 里的例子有String.intern()

代理(Proxy)

控制对象访问的中间层。可实现权限校验(保护代理)、远程调用(远程代理)、性能优化(缓存代理)等功能。与装饰器区别在于侧重访问控制而非功能增强。

桥接(Bridge)

将一个大类或一系列紧密相关的类拆分为独立的层次结构。典型应用如 GUI 开发中,将窗口抽象与平台具体实现分离,支持跨平台扩展。

行为型模式

命令(Command)

将操作封装为对象,支持撤销、重放、队列等高级功能。文本编辑器中的撤销栈即通过存储命令对象实现历史操作回溯。

迭代器(Iterator)

集合遍历的标准解决方案。Java 通过 Iterable/Iterator 接口规范化。Iterator 只能被遍历一次,而 Iterable 可以被多次使用并从中获取新的 Iterator。Java 的 for-in 语法可以用于任意 Iterable

观察者(Observer)

用于实现订阅通知机制。Observer 订阅 Observable。事件发生时,Observable 调用所有订阅者的方法以通知事件。

状态(State)

管理对象行为随内部状态变化的模式。有限状态机(如游戏角色动作控制)是其典型应用。如果只有少数几种状态,可以在单个类中实现。如果状态数量比较多,为了更清晰地展示类在不同状态下的行为,可以把不同状态下的行为拆分到不同的状态类中,而主类需要保存当前所处的状态和把行为委派给状态类。

策略(Strategy)

对于同一个任务,可以有不同的策略去完成。例如遍历一棵二叉树,可以前序遍历、中序遍历、后序遍历、层次遍历。把不同策略的算法实现在不同的类中,即是策略模式。策略模式与状态模式的区别是,状态可以转换为其它状态,而不同策略之间相对比较独立。

模板方法(Template Method)

在超类中定义算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。实际上不一定需要通过超类子类的方式来实现,如 Java 的 Collections.sort() 通过 Comparator 参数实现变种,比传统继承方式更灵活。

访问者(Visitor)

用于访问复杂的复合数据结构。例如编译器在编译时需要访问解析出的语法树,语法树上有各种不同类型的节点,编译器需要访问这些节点。语法树上的各类节点需要实现 accept(Visitor) 方法,编译器需要实现访问各种类型节点的 visit(Node) 方法。

责任链(Chain of Responsibility)

将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。例如工作中的升级机制,如果一件事情你能处理,你就处理;如果你无法处理,就上报给你的经理。浏览器的事件冒泡与捕获也是一个例子。具体实现方面,把不同的处理者放到不同的类中,客户端自行把不同的处理者组装成链。

中介者(Mediator)

限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。事件总线是典型实现,有效降低系统耦合度,但中介者本身可能成为复杂度瓶颈。

备忘录(Memento)

实现状态快照与恢复。关键设计是由要保存的对象本身实现保存和恢复接口。生成的备忘录只能由原对象类使用,其它类无法访问。

参考