跳到主要内容

原型模式

通过声明一个包含 clone 方法的接口,原型模式将创建对象拷贝(克隆)的职责委派给对象所属的类。

结构

依照实现,可以划分为简单实现和注册表实现两种。

简单实现

原型模式简单实现示意图原型模式简单实现示意图

在简单实现中,通常会定义一个包含 clone 方法的抽象类或接口,以及具体的实现类。具体的实现类会实现 clone 方法,以便返回一个当前对象的拷贝。

clone 方法内部通常通过调用拷贝构造函数(以自身类对象为参数的构造函数)来实现创建副本对象;如果语言不支持函数重载,也可以通过一个特殊方法或是和 工厂方法 模式结合使用来实现。

注意

需要注意的是,如果具体的实现类还有子类,那么子类也需要实现 clone 方法,避免错误生成父类对象。

注册表 / 缓存实现

原型模式注册表 / 缓存实现示意图原型模式注册表 / 缓存实现示意图

在注册表实现中,会定义一个注册表类,用于存储原型对象。注册表类会提供一个方法,用于将特定的原型对象关联到固定的标识符上;此后,可以通过这个标识符来获取原型对象的拷贝。

由于存储了多个不同的原型对象,该实现又被称作缓存实现。

应用场景

  • 希望复制某个对象,但不希望复制的过程受到对象的具体类的限制

优缺点

优点

  • 克隆对象的同时而无需与它们所属的具体类相耦合
  • 可以使用一系列预生成的、 各种类型的对象作为原型,避免多次调用初始化代码
  • 可以用继承以外的方式来处理复杂对象的不同配置

缺点

  • 克隆包含循环引用的复杂对象可能会非常麻烦

代码示例

以下代码展示了一个原型模式的实现。Prototype 是一个接口,定义了 clone 方法。Door 是一个具体原型类,它实现了 clone 方法来创建自身的副本。

这个例子特别强调了浅拷贝深拷贝的区别:

  • 浅拷贝 (copy.copy):只复制对象本身,而不复制其内部的嵌套对象。因此,当修改克隆对象中嵌套对象(Address)的属性时,原始对象中的嵌套对象也会被修改,因为它们共享同一个 Address 实例。
  • 深拷贝 (copy.deepcopy):会递归地复制对象及其所有嵌套对象。因此,修改克隆对象的嵌套对象不会影响原始对象。

客户端代码通过调用 clone 方法来获取 Door 对象的副本,而无需关心其具体的创建过程。这使得创建新对象变得高效,特别是当对象初始化过程很复杂时。