设计模式之 原型模式
原型模式是一种创建型设计模式,它通过复制现有的实例来创建新的对象,而不是通过传统的构造方法。通过这个模式,可以避免重复的初始化操作,尤其适用于当创建一个对象需要耗费较大资源或时间时。原型模式的核心思想是“通过克隆现有对象来创建新的对象”,这样既能减少对象创建的开销,又能保证新对象的创建更加灵活。
1. 原型模式的定义
原型模式的定义为:使用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。具体来说,它的核心是通过实现一个 clone
方法,使得我们可以复制(克隆)对象的状态而无需重新构造。这个方法通常会返回对象的一个副本,而不是重新实例化一个新对象。
2. 原型模式的结构
原型模式通常由以下几个角色组成:
- Prototype(原型接口):定义了一个克隆方法,所有具体的原型类都需要实现这个方法。
- ConcretePrototype(具体原型):实现了
Prototype
接口,并且通过clone
方法来复制自己的实例。 - Client(客户端):使用原型对象,并通过调用克隆方法来获取一个新对象,而不是通过构造方法来创建对象。
3. 原型模式的优点
原型模式的优点主要体现在以下几个方面:
-
性能提升:如果创建对象的过程比较繁琐且需要耗费大量时间,克隆现有对象通常比重新创建一个对象更快。因此,原型模式特别适用于需要大量对象创建的情况,尤其是在构建复杂对象时。
-
简化对象创建:使用原型模式可以避免使用
new
关键字显式地创建对象,而是通过克隆一个已有的对象来生成新对象,从而简化了对象的创建过程。 -
减少内存开销:对于一些复杂的对象,可以通过克隆方式避免重复创建,节省内存空间。比如,当需要创建一个与现有对象类似的多个对象时,原型模式可以避免反复初始化那些相同的属性。
-
易于扩展:通过增加新的原型类,可以非常方便地扩展对象创建的方式,而不需要修改现有的代码。
4. 原型模式的缺点
原型模式虽然有很多优点,但也有一些缺点和局限:
-
复杂性:对于某些对象,克隆过程可能会比较复杂。特别是如果对象包含复杂的状态(如对外部资源的引用),克隆对象可能需要更复杂的逻辑,甚至涉及深拷贝(deep copy)。
-
无法复制某些对象:一些不可复制的对象(例如线程、数据库连接、文件流等)可能无法通过克隆实现,这限制了原型模式的使用场景。
-
维护问题:在使用原型模式时,如果对象包含复杂的结构,可能会导致对象的一些属性没有完全复制,进而导致逻辑上的问题。特别是在多线程环境中,确保原型对象的一致性会变得更为困难。
5. 原型模式的分类
原型模式可以分为两种主要的克隆方式:
-
浅拷贝(Shallow Copy):即仅复制对象的基本类型属性,对于引用类型的属性,只复制引用,而不复制对象本身。这样,源对象和目标对象会共享同一个引用类型的属性。
-
深拷贝(Deep Copy):即不仅复制对象的基本类型属性,还会递归地复制引用类型的属性。这样,源对象和目标对象的引用类型属性是完全独立的。
6. 原型模式的应用场景
原型模式适用于以下几种场景:
-
对象创建开销较大:当创建一个对象非常耗费时间或资源时,使用原型模式可以通过克隆已有对象来避免重复的资源消耗。
-
对象的属性或状态可以变化,但结构相对固定:如果对象的属性结构较为固定,但又需要动态调整其中的一些属性,可以通过克隆原型来高效地创建新对象。
-
原型对象有多个副本:在某些场景中,可能需要多个对象具有相同的初始状态(如游戏中的多个相似角色),而通过克隆已有对象来创建副本更为高效。
-
需要避免重复的复杂对象初始化:当对象的初始化过程非常复杂(如大量的计算和数据加载),原型模式可以通过克隆已有对象来避免重复的计算,减少系统负担。
7. 原型模式的实现示例
以 Java 为例,下面展示一个简单的原型模式实现。
-
实现具体原型类(
ConcretePrototype
)
我们创建一个具体的原型类 Citation,让他实现Cloneable接口,并重写Object类的 clone
方法。
public class Citation implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
public void show(){
System.out.println(name+"同学获得了奖状");
}
}
-
客户端代码(
Client
)
客户端代码通过 clone
方法创建新对象,而无需通过构造方法手动实例化对象。
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Citation citation = new Citation();
citation.setName("张三");
Citation citation1 = citation.clone();
citation1.setName("李四");
citation.show();
citation1.show();
}
}
-
运行结果
深拷贝
如果 Citation类中包含一些引用类型的属性,我们可以通过序列化的方式,进行深拷贝。