原型模式指的是从目前已经有的实例复制
出一个新的实例,主要用于一些对象的创建过程比较耗时的情况。比如说对象的某些字段需要进行大量计算或者查询大量数据才能得到。如果每次创建对象都重新计算这些字段,会造成资源和时间的浪费,如果我们能从现有的对象中复制出一个新的实例,然后再根据需要稍做修改就可以避免浪费。
在Java中,我们不需要自己定义原型相关的接口和方法,只需要申明实现Cloneable,再重写clone方法即可。如下,假设SearchEngine在创建的时候需要加载核心数据,这是一个耗时耗性能的操作。
1public class SearchEngine implements Cloneable {
2 public String name;
3 private CoreData data;
4
5 public SearchEngine() { }
6
7 public SearchEngine(String name) {
8 this.name = name;
9 this.data = CoreData.load();
10 }
11
12 @Override
13 protected Object clone() {
14 SearchEngine copy = new SearchEngine();
15 copy.name = name;
16 copy.data = data;
17 return copy;
18 }
19}
使用的时候,直接调用当前实例(原型)的clone方法,就能得到一个新的对象,而且无需再重新加载核心数据。
SearchEngine google = new SearchEngine("Google");
SearchEngine baidu = (SearchEngine) google.clone();
baidu.name = "Baidu";
不过在clone方法的实现上有牵扯出一个新问题,那就是使用深拷贝还是浅拷贝,比如说上面的CoreData属性,我们直接赋值给了copy对象,这样他们两个SearchEngine使用的就是同一个CoreData对象,如果某一方修改这个CoreData内部数据,两个SearchEngine都会受到影响。
如果是使用深拷贝的话,我们应该为copy对象重新创建一个CoreData对象,然后将原型中的CoreData对象的属性复制到copy对象的CoreData对象中,如果CoreData这个类创建也比较麻烦呢?个人的建议是让CoreData也实现Cloneable接口和clone方法,那么SearchEngine中的clone方法就变成了这样。
@Override
protected Object clone() {
SearchEngine copy = new SearchEngine();
copy.name = name;
copy.data = (CoreData) data.clone();
return copy;
}
使用原型模式可以更方便的创建相似的对象,避免多次进行初始化工作。这里引入了深拷贝和浅拷贝的概念,在实际开发中,具体使用那种方式需要根据情况而定。