目录
创建型
结构型
原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制现有的对象(即原型)来创建新对象,而不是每次都通过new操作符来创建对象。这种模式适用于创建新对象的成本较大(如初始化耗时、占用资源较多)或者创建过程较复杂的场景,通过克隆原型对象可以快速、便捷地生成相似或相同状态的新对象。
模式结构
原型模式通常包含以下角色:
- 原型(Prototype) :定义一个克隆自身的接口,通常包含一个
clone()
方法。 - 具体原型(Concrete Prototype):实现原型接口,提供克隆自身的具体实现。具体原型类需要能够复制自身的状态,并可能包含必要的辅助方法来支持复制过程。
工作原理
- 客户端 :通过调用具体原型对象的
clone()
方法来创建新对象,无需关心对象的内部构造细节。 - 具体原型 :实现
clone()
方法,负责复制自身的状态,并可能需要处理深层次对象的递归复制。新创建的对象与原对象状态相同,但具有独立的标识(即不同的内存地址)。
优缺点
优点
- 简化对象创建过程:对于复杂的对象,使用原型模式可以简化对象的创建过程,避免重复初始化或执行耗时的操作。
- 提高性能:通过复制现有对象创建新对象,特别是在对象初始化成本较高的情况下,可以显著提高性能。
- 支持动态增加或修改产品类:如果产品类需要动态添加或修改,使用原型模式可以避免对客户端代码产生影响。
缺点
- 对象必须支持克隆:不是所有的对象都能很容易地实现克隆,尤其是包含复杂状态或引用其他对象时,克隆实现可能变得复杂。
- 深拷贝与浅拷贝问题:在复制包含其他对象引用的状态时,需要考虑是否需要深度复制这些引用对象,否则可能导致数据不一致或意外共享状态。
适用场景
- 对象创建成本较高:当创建新对象需要消耗大量资源、执行复杂操作或初始化时间较长时,使用原型模式可以有效提高效率。
- 需要动态创建相似或相同状态的对象:如游戏中的角色复制、文档模板应用、数据恢复场景等,通过克隆原型对象快速生成新对象。
- 需要避免对象之间的相互依赖:通过复制已有对象来创建新对象,可以减少对象间的依赖关系,降低系统的耦合度。
代码示例(以Java为例)
在Java中实现原型模式,可以利用Java内建的Cloneable
接口和Object
类提供的clone()
方法。下面是一个简单的Java代码示例:
java
// 原型接口(由于Java中没有显式的原型接口,此处省略)
// 具体原型类实现Cloneable接口以支持克隆
public class ConcretePrototype implements Cloneable {
private String attr1;
private String attr2;
public ConcretePrototype(String attr1, String attr2) {
this.attr1 = attr1;
this.attr2 = attr2;
}
// 提供公共的clone方法
@Override
public ConcretePrototype clone() throws CloneNotSupportedException {
return (ConcretePrototype) super.clone();
}
// 其他方法、属性...
public String getAttr1() {
return attr1;
}
public String getAttr2() {
return attr2;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
try {
ConcretePrototype prototype = new ConcretePrototype("value1", "value2");
ConcretePrototype clonedObject = prototype.clone();
System.out.println(clonedObject.getAttr1()); // 输出:value1
System.out.println(clonedObject.getAttr2()); // 输出:value2
} catch (CloneNotSupportedException e) {
// 不应该发生,因为ConcretePrototype实现了Cloneable接口
e.printStackTrace();
}
}
}
在这个Java示例中:
ConcretePrototype
类实现了Cloneable
接口,表明它可以被克隆。- 重写了
Object
类的clone()
方法,并将其声明为public
,以便客户端可以直接调用。注意,虽然Cloneable
接口没有实际的方法定义,但它是一个标记接口,用于指示对象支持克隆操作。- 在
clone()
方法中,调用super.clone()
来执行实际的克隆过程。这会创建一个浅拷贝,即原始对象和克隆对象共享不可变的基本类型和对象引用。如果类中包含复杂对象或可变集合,可能需要在clone()
方法中进行深度拷贝,以确保新对象的独立性。- 客户端代码通过调用
prototype.clone()
来创建新对象,捕获可能出现的CloneNotSupportedException
异常(尽管在正确实现Cloneable
的情况下,此异常通常不会抛出)。
请注意,Java的clone()
方法默认执行的是浅拷贝,如果对象内部包含可变的复杂对象或集合,需要在clone()
方法中手动进行深拷贝,以确保新对象的状态完整独立。例如,如果ConcretePrototype
类中有一个可变的列表成员变量,需要在clone()
方法中对其进行单独复制:
java
private List<String> items;
// ...其他代码...
@Override
public ConcretePrototype clone() throws CloneNotSupportedException {
ConcretePrototype clone = (ConcretePrototype) super.clone();
clone.items = new ArrayList<>(this.items); // 深拷贝列表
return clone;
}
代码示例(以Python为例)
python
import copy
# 原型接口
class Prototype:
def clone(self):
raise NotImplementedError("Subclasses must implement this method")
# 具体原型
class ConcretePrototype(Prototype):
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2
def clone(self):
return copy.deepcopy(self)
# 客户端代码
def main():
prototype = ConcretePrototype("value1", "value2")
cloned_object = prototype.clone()
print(cloned_object.attr1, cloned_object.attr2) # 输出:value1 value2
if __name__ == "__main__":
main()
在这个Python示例中:
Prototype
类作为原型接口,定义了clone()
方法,要求子类必须实现。ConcretePrototype
类继承自Prototype
,实现了具体的clone()
方法。这里使用copy.deepcopy()
来实现深度克隆,确保新创建的对象与原对象状态相同且具有独立的标识。- 客户端代码通过调用
ConcretePrototype
对象的clone()
方法来创建新对象,无需关心对象的内部构造细节。新创建的对象与原对象状态相同,但具有独立的标识。