Demo 地址: https://github.com/ooblee/HelloDesignPattern
1. 定义
原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。
就是对已有实例的直接复制。
对于一些复杂对象,不需要重复配置或者初始化,以当前对象为原型拷贝一个新对象出来。
2. 设计
原型主要角色:
- 抽象原型类,声明克隆方法。
- 具体原型类,实现克隆方法,返回复制对象。
- 客户类,调用原型进行克隆。
类图如下:
2.1. 通用实现
在 clone 方法中创建新对象,然后把内容一个个复制过去。
抽象克隆类,克隆方法为 cloneObject。
public interface IPrototype {
IPrototype cloneObject();
}
具体实现类,实现克隆方法,会把当前对象的属性拷贝一份过去。
public class Prototype implements IPrototype {
private String attr;
public Prototype() {
}
public IPrototype cloneObject() {
Prototype prototype = new Prototype();
prototype.attr = attr;
return prototype;
}
public void setAttr(String attr) {
this.attr = attr;
}
public String getAttr() {
return attr;
}
@Override
public String toString() {
return "attr:" + attr;
}
}
调用方式,直接使用 cloneObject 生成新对象。
public class TestPrototype {
public static void main(String[] args) {
Prototype prototype = new Prototype();
prototype.setAttr("hello");
System.out.println(prototype.toString());
// 复制对象
IPrototype cloneObject = prototype.cloneObject();
System.out.println(cloneObject.toString());
}
}
2.2. Java Clone 方式
Object 已经内置了 clone 的默认实现,本地方法,作用为在内存空间开辟一个新对象,并把属性值复制一份过去。
如果是引用,则把引用复制一份过去,但不会复制引用的对象。
protected native Object clone() throws CloneNotSupportedException;
Java 使用 Cloneable 接口来标记原型类,实现原型模式。
支持克隆的类实现要覆盖 Object 的 clone 方法。
详细步骤如下:
- 覆盖 Object 的 clone 方法。
- 在 clone 中调用 super.clone()。
- 需要实现 Cloneable 标记接口,否则会报异常。
原型类 Prototype:
public class Prototype implements Cloneable {
private String attribute;
private ComplexObject complexObject;
@Override
protected Object clone() throws CloneNotSupportedException {
Prototype prototype = (Prototype) super.clone();
prototype.complexObject = (ComplexObject) this.complexObject.clone();
return prototype;
}
...
}
2.3. 深克隆和浅克隆
Java 的复制都是值复制。
- 基本类型的话没问题,直接复制一份新的值。
- 引用类型的话是复制引用,但不会创建新的对象。所以引用会指向堆中的同一个对象。
浅克隆就是只进行值复制,不为引用类型开新对象。直接调用 Object 的 clone 方法。
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
深克隆是引用类型的对象也进行克隆。在 clone 的时候,再调用一下成员变量对象的 clone 方法开辟新的内存。
@Override
protected Object clone() throws CloneNotSupportedException {
Prototype prototype = (Prototype) super.clone();
prototype.complexObject = (ComplexObject) this.complexObject.clone();
return prototype;
}
3. 应用
这些应用场景可以考虑使用:
- 创建新对象耗时耗资源,但变化较小。
- 需要创建大量相同或者相似的对象。
- 需要保存对象的状态,可以配合备忘录模式实现。
4. 特点
4.1. 优势
- 简化创建:直接复制,提高效率。
- 接口简单:不需要增加工厂来创建对象。
4.2. 缺点
- 每个原型类都要实现克隆方法。
- 深浅克隆要注意。