设计模式之原型模式

概述

原型模式(Prototype)属于创建型模式,用于创建重复对象,又能保证性能。原型模式的核心思想是通过拷贝指定的原型实例(对象),创建跟对象一样的新对象。

适用环境

  • 当初始化对象需要消耗很多资源时,包括数据、硬件资源等。
  • 通过 new 产生对象需要非常繁琐的数据准备或访问权限时。
  • 当一个对象会被多个调用者使用,且各个调用者都要修改其值的时候。
  • 当一个类的实例就只有几个不同状态的组合中的一种时,建立相应数量的原型对象并克隆原型可能比每次手工实例化更方便一些。

设计理念

原型模式的核心是一个 clone 方法,通过调用这个方法完成原型对象复制。

在 java 中直接实现 Cloneable 接口即可,这个接口没有定义方法,只作为一个标识,表明这是一个可以直接拷贝的类。

注意原型模式中的拷贝方式,需要考虑是使用浅拷贝还是深拷贝,以及深拷贝的层数。实现 Cloneable 接口,使用 Object 的 clone 方法就是浅拷贝,如需使用深拷贝需要自己实现。

  • 浅拷贝:被拷贝对象的所有变量值都与原对象相同,而对象中对其他对象的引用仍然指向原来的对象。
  • 深拷贝:拷贝对象和下层的引用对象,对象中对其他对象的引用指向的是拷贝得到的新对象。

优缺点

隐藏创建过程

直接通过原型对象创建另一个可定制的对象,用户不需要关心对象创建的细节。

性能优良

原型模式是对内存中二进制流进行拷贝,比直接 new 一个对象性能更好,特别是在一个循环体中创建大量对象时,或者对象很大时。

不受构造函数约束

由于拷贝是直接在内存中执行的,不会执行构造函数,所以不受构造函数的约束。

但正因为缺少了约束,在使用时需要考虑到这点。比如单例模式中,构造方法是 private 的,一般情况下无法访问,但通过 clone 却可以绕过构造方法,直接创建对象。

实现克隆方法需要通盘考虑

实现原型对象的克隆方法需要考虑类的功能,对于已有类,特别是引用了一个不能序列化对象的或含有循环结构的,实现起来会很麻烦。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Prototype implements Cloneable {
@Override
protected Prototype clone() {
Prototype prototype = null;
try {
prototype = (Prototype) super.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return prototype;
}
}

public class ConcretePrototype extends Prototype {
public void show(){
System.out.println("原型实现类");
}
}


public class Client {
public static void main(String[] args) {
ConcretePrototype concretePrototype = new ConcretePrototype();
for (int i = 0; i < 10; i++) {
ConcretePrototype cloneObj = (ConcretePrototype) concretePrototype.clone();
cloneObj.show();
}
}
}

参考资料

总结

原型模式是最简单的设计模式之一,已经与 java 融为一体了,通常情况下会搭配其他设计模式一起使用,一般和工厂模式一起出现,通过clone一个对象,然后通过工厂方法提供给调用者。