原型模式,根据现有的实例变量( A ),复制(克隆)出相同类型的实例变量 ( B )。
要理解原型模式的实质,核心的要点是搞清楚 “ 深复制 ” 和 “ 浅复制 ”。
一,“ 深复制 ” 和 “ 浅复制 ” 的概念和区别
浅复制:使用一个已知实例 ( A ) 对新创建实例 ( B ) 的成员变量逐个赋值,这个方式也被称为浅拷贝
深复制:不仅要复制对象的所有非引用类型成员(即基本数据类型变量,如int、boolean、char等)变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值。
通过以上概念可以得知:
浅复制时,实例变量中的引用变量的值(该值是地址,不是变量的实际内容)也是相同的,即指向(堆中)同一个对象。
深复制需要做的是:在堆中新建引用类型的成员实例对象,并将该新建的成员实例对象的地址赋值给新实例变量 ( B ) 的成员(引用类型,值是地址)。
二, 原型模式的实现:实现Cloneable接口(Java)
原型模式本质上是要实现复制(克隆)。
复制又分为 “ 深复制 ” 和 “ 浅复制 ”。Java 中通过让一个类实现 cloneable 接口,并重写 clone() 函数,在 clone() 函数中,执行旧对象向新对象进行成员变量赋值操作,实现一个对象的复制(克隆)。
简单的“成员变量的逐一拷贝赋值”实现的是浅复制。
要保证“深复制”的实现,需要该对象引用的其他对象(即对象中的非基本类型成员变量)也要实现 Cloneable 接口并重写 clone()方法。
按照上面的结论,实现以下代码 Body 类组合了 Head 类,要想深拷贝 Body 类,必须在 Body 类的 clone 方法中将 Head 类也要拷贝一份。代码如下:
1.static class Body implements Cloneable{
2. public Head head;
3. public Body() {}
4. public Body(Head head) {this.head = head;}
5. @Override
6. protected Object clone() throws CloneNotSupportedException {
7. Body newBody = (Body) super.clone();
8. newBody.head = (Head) head.clone();
9. return newBody;
10. }
11.}
12.static class Head implements Cloneable{
13. public Face face;
14. public Head() {}
15. @Override
16. protected Object clone() throws CloneNotSupportedException {
17. return super.clone();
18. } }
19.public static void main(String[] args) throws CloneNotSupportedException {
20. Body body = new Body(new Head(new Face()));
21. Body body1 = (Body) body.clone();
22. System.out.println("body == body1 : " + (body == body1) );
23. System.out.println("body.head == body1.head : " + (body.head == body1.head));
24.}
打印结果为:
1. body == body1 : false
2. body.head == body1.head : false
注意:以上示例代码中,Head 在 clone 时不保证是 “ 深复制 ”,因为 Head 中的 Face 也是个引用变量,是否是 “ 深复制 ” 取决于:原 Head 对象新 “ 克隆 ” 出的新 Head 对象中的 Face 是如何赋值的。
三,原型模式的结构图
![](https://i-blog.csdnimg.cn/blog_migrate/20aeaac4d06bfa58cd9d60470794126c.png)
我个人理解,所谓的原型模式就是要实现一个可以自我克隆的接口,实际编码时需要重点考虑的是克隆如何实现,以及克隆的效果如何,是 “深克隆” 还是 “浅克隆”。