设计模式之原型模式

什么是原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

原型模式是最后一种创建型设计模式了,这也是一种非常简单的设计模式,下面来具体看实例。

举个栗子

原型模式的模型图

原型模式的核心就是java中的克隆机制,Prototype类需要实现Cloneable接口,覆盖clone方法,然后就实现了原型模式,通用代码如下

1
2
3
4
5
6
7
8
9
10
11
12
public class Prototype implements Cloneable {
@Override
protected Object clone() {
Prototype prototype = null;
try {
prototype = (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
//处理异常
}
return prototype;
}
}

原型模式就是这么简单,是比单例模式还简单的设计模式,下面来看一看具体的使用。

适用范围

使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显,在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

优点缺点

原型模式的优点是性能好,能够极大程度上降低创建新对象带来的系统开销。

另一方面,运行模式避开了构造方法的约束,这一点既是优点也是缺点,需要结合实际情况。

注意事项

首先要记住,使用克隆的方式创建对象是不会触发构造方法的,原因上面提到过。

另一个注意的点就是需要clone的类中任何成员不要用final修饰。

还有一个很重要的问题,涉及到java中克隆的特性,那就是浅拷贝和深拷贝

浅拷贝

看一下下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
public class Prototype implements Cloneable {
private ArrayList list = new ArrayList();
public Prototype clone(){
Prototype prototype = null;
try{
prototype = (Prototype)super.clone();
}catch(CloneNotSupportedException e){
//处理异常
}
return prototype;
}
}

这样就可以复制出一个新对象吗,答案是否定的,这样创建的对象会和旧对象公用同一个list,也就是说list实际上没有被复制,两个对象共享一块空间,问题就很严重了。为什么会这样呢,因为java总clone方法只会对基本数据类型和String进行复制,其他的内容都只是浅拷贝,这是一种及其不安全的做法,于是就引出了深拷贝的概念。

深拷贝

在上面的例子中做一点小的改动

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Prototype implements Cloneable {
private ArrayList list = new ArrayList();
public Prototype clone(){
Prototype prototype = null;
try{
prototype = (Prototype)super.clone();
prototype.list = (ArrayList) this.list.clone();
}catch(CloneNotSupportedException e){
//处理异常
}
return prototype;
}
}

只是添加了一行代码,此时就可以实现深拷贝。在执行过程中把不能自动拷贝的数组,对象引用等等内容手动拷贝一份,这样完成的才是安全的拷贝。

原型模式要注意的大概就这么多,至此,五种创建型模式全部结束了,接下来会介绍结构型模式。

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!