理解三个核心创建模式

软件设计模式是经过战斗测试的解决反复出现的设计问题的蓝图。 最常见的使用模式包括:关于物体如何被即时化的创造模式 — — 银河、工厂和原型。 选择正确的一种直接冲击代码的可维护性、性能和可扩展性。 这个扩展的指南深入到每一种模式中,探索现实世界的情景,并提供可操作的标准帮助您做出知情的决定。

Singleton 模式: 统治全部的单一实例

Singleton模式确保一个类有一个完全的实例,并提供了一个全局访问点。它是最简单的模式之一,但经常被滥用。核心思想是控制即时进程,这样无论请求的类有多少次,都返回同一个对象。

单子顿如何工作

通常情况下,Singleton类具有一个私有构造器和返回实例的静态方法。第一个调用创建对象;随后调用重复使用同一实例。在多线程环境中,需要同步来防止可能产生多个实例的种族条件。

public class DatabaseConnectionPool {
 private static DatabaseConnectionPool instance;
 private DatabaseConnectionPool() { /* initialization */ }
 public static synchronized DatabaseConnectionPool getInstance() {
 if (instance == null) {
 instance = new DatabaseConnectionPool();
 }
 return instance;
 }
}

当Singleton闪耀时

  • 管理共享资源:连接池,日志服务,或配置管理器从单一的点协调中受益.
  • 全局状态: 当一个全应用缓存或注册需要一致的存取时.
  • 硬件或OS级资源:[文件系统,打印机拼接器,或窗口管理器通常只允许一个实例.

避免的常见陷阱

  • 过度使用:[ 利用Singleton为一切带来隐藏的依赖性,使单位测试变得硬化,因为你无法轻易地用一个模拟器取代实例.
  • Thread-security over: 经典同步方法可以成为瓶颈. 诸如急速初始化或双检查锁(带有挥发性)等替代方法可以减少争议.
  • 紧接: 由于全局接入点是硬编码的,客户端会与混凝土Singleton类结合,违反了依赖性反转原则.

尽管有这些缺点,但当您真正需要一个单一的、全球可访问的对象时,Singleton仍然有用。关于更深入的理解,请参见 重构古鲁的Singleton指南

工厂模式: 授权对象创建

Factory 模式封装对象即时逻辑,允许子类决定哪个类别进行即时处理。它主要有两种口味: Factory Method (一种返回新对象的单一方法)和[Abstract Factory [ (一种由相关工厂方法组成的家族) 两种都从混凝土类中解开客户代码,促进松散的耦合和更容易的扩展性.

工厂方法详细

定义创建对象的界面, 但让子类更改将要创建的对象类型。 例如, 对话框类可能有一个方法 [ [[FLT: 1]] 。 子类如 WindowsDialog 和 LinuxDialog 覆盖此方法以返回平台特定按钮 。

abstract class Dialog {
 abstract Button createButton();
 public void render() {
 Button okButton = createButton();
 okButton.onClick();
 }
}
class WindowsDialog extends Dialog {
 Button createButton() { return new WindowsButton(); }
}

这样的模式在下列情况下是理想的:

  • 类不能预见它必须创建的对象的类别 。
  • 您想要将对象创建逻辑定位在一个地方 。
  • 系统需要独立于其对象的构造方式.

抽象工厂:生产相关物品的家庭

抽象工厂提供了创建关联或依赖对象家族的接口,而未指定其混凝土类. 想想GUI工具包,它必须产生一个按键,复选框,以及滚动条,这些按键在指定主题(如材料,Cupertino)下看起来一致. 客户端使用抽象工厂界面来获取产品,混凝土工厂(MatrialFactory,CupertinoFactory)生成正确的变体.

选择此模式时:

  • 该系统必须配置成多个产品家族中的一个。
  • 您想要强制要求产品之间保持一致性 。
  • 增加新产品家庭需要对现有代码进行最小的修改.

在工厂和其他模式之间作出决断

当对象创建复杂或需要运行时交换执行时,工厂是您要进入的。它比Singleton更灵活,因为它不限制实例的数量,而只是集中创建。与原型不同的是,工厂从零开始创建新的实例,而不是复制现有的实例。对于两种变体,请访问 重新确定古鲁工厂方法的页面[ Abstract Fact Factory页面

原型模式: 克隆取代构造

原型模式通过复制一个已有对象——原型来创建新对象。 当即时化费用昂贵(例如,重数据库查询、复杂的几何计算)或对象配置耗时,它特别有价值。您不从零开始构建,而是克隆一个预配置实例,并按需要对其进行调整。

克隆机械师:浅色对深层复制

大多数编程语言都提供了内置克隆方法(),在Java,在Python,或分布在JavaScript中。但是,必须仔细注意复制是浅(共享可变对象的参考文献)还是深(完全独立). 深复制递录复制克隆所引用的所有对象。在执行Prototype时,必须决定复制的级别与您的使用大小写相符.

class MazePrototype {
 public MazePrototype clone() throws CloneNotSupportedException {
 return (MazePrototype) super.clone(); // shallow copy
 }
}

原型的理想情景

  • 核心对象创建: 例如,从文件中装入一个大配置或者生成一个复杂的几何网格.
  • Dynamic runtime对象: 当系统必须生成在运行时间确定类型的新对象(例如,在从预定义模板中产化的游戏中的敌人类型)时.
  • 减少子类爆炸:[ 与其为微小的变异创建许多子类,不如克隆一个原型,调整几个属性.

原型登记和缓存

您可以通过实施一个注册系统—— 由密钥索引的预建原型的中央存储系统, 进一步采取原型。 客户请求按密钥进行原型, 复制并定制。 在某些情况下, 原型与注册系统相结合, 可作为工厂或Singleton 的轻量级替代。 详细走过, 请参见 [ [FLT: 0]] 重构 Gru 的原型指南 。

边边比较:单子、工厂、原型

为了帮助您选择,下表突出关键差异:

PatternInstance CountCreation MechanismBest For
SingletonExactly oneSelf-managed global accessShared resources, global state
FactoryMultiple instances (or families)Centralized creation logicDecoupling client from concrete classes, complex creation
PrototypeMultiple instances cloned from a templateCloning (shallow/deep copy)Expensive instantiation, runtime object generation

当模式重叠或组合时

  • 辛莱顿+工厂: 工厂本身可以是单子(例如每个平台一个抽象工厂),这把全球接入与集中创建结合起来.
  • 原型+工厂: 原型注册可以充当工厂——你克隆原型而不是叫构造者,这在产卵实体时的游戏开发中特别有用.
  • Prototype + Singleton: 一个原型物体可能是单子,意思是每个类型只存在一个原型实例,尽管克隆人不是单子.

实际决定框架

当遇到设计问题,需要建立创建模式时,请按以下顺序问这些问题: 1.

  1. 我在整个申请过程中需要一次吗? 如果有,请考虑Singleton。 但要确保真正需要全球共享状态,而且检验能力不会受到影响。
  2. 对象创建是否复杂或可能改变? 如果有,则使用工厂方法或摘要工厂。这在您预计以后会添加新的对象类型时特别有用。
  3. 对象创建是性能瓶颈,还是我需要很多只稍有不同的例子? 如果是,原型可以通过克隆一个模板来节省时间和内存.
  4. 多个模式能否达到同样的目的? 权衡权衡。例如,如果目标共享不可变数据,一个飞行量度模式可能会减少内存而不是原型。

工程软件中的真实世界实例

工程应用经常混合这些模式。一个CAD系统可能会使用Singleton来为用户首选项管理器,Factory来创建各种几何形状(圆形,多边形,丝状),以及克隆一个复杂组装然后修改的原型。一个模拟引擎可以使用Factor来创建不同的解析对象,用于复制粒子系统配置的原型,以及用于记录所有模拟步骤的日志服务。

结论:不要让模式化您的设计

单子、工厂和原型是基本创造模式,但并不是银子弹。 最好的选择来自理解你的系统限制:比如控制的必要性、物体创造的复杂性和新事件的成本。 总是倾向于清晰和可检验性,而不是模式纯度。 当怀疑时,从工厂开始 — — 它提供最干净的解耦,如果情况需要,它可以被原型或单子顿取代或扩充。

通过掌握这三种模式,您可以装备一个多功能工具包,用于构建强健灵活的工程软件. 欲进一步阅读,请探索关于软件设计模式的维基百科文章和 重构古鲁对创造模式的概述.