孙悟空可以用猴毛根据自己的形象复制出多个跟自己长得一模一样的猴子出来,这种技巧在面向对象软件设计领域被称为原型模式,孙悟空则被称为原型对象。在面向的对象系统中也可以通过复制一个原型对象得到多个与原型对象一模一样的新对象,这就是原型模式的动机。
定义
使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
工作原理
将一个原型对象传给要发动创建的对象,这个发动创建的对象通过请求原型对象复制自己来实现创建过程。
通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,通常对克隆所产生的对象进行修改不会对原型对象造成任何影响,每一个克隆对象都是相互独立的。
结构
Prototype(抽象原型类)
它是声明克隆方法的接口,是所有具体原型类的公共父类,它可以是抽象类也可以是接口,甚至还可以是具体实现类。
ConcretePrototype(具体原型类)
它实现在抽象原型类中声明的克隆方法,在克隆方法中返回一个自己的克隆对象。
Client(客户类)
在客户类中,让一个原型对象克隆自身从而创建一个新的对象,只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统就要较好的可扩展性,增加或更换具体原型类都很方便。
应用实例 - 快速创建工作周报
这里Object充当抽象原型类
/**
*
* @ClassName WeeklyLog
* @Description 工作周报 - 具体原型类
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class WeeklyLog implements Cloneable {
private String name;
private String date;
private String content;
/**
* 克隆方法,此处使用Java语言提供的浅克隆机制
*/
public Object clone() {
Object obj = null;
try {
obj = super.clone();
return obj;
}catch (CloneNotSupportedException e) {
System.out.println("不能复制");
return null;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
/**
*
* @ClassName Client
* @Description 客户端测试类
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class Client {
public static void main(String[] args) {
WeeklyLog log_previous = new WeeklyLog();
log_previous.setName("张三");
log_previous.setDate("2019年第12周");
log_previous.setContent("这周工作很忙,每天加班");
System.out.println("****周报****");
System.out.println(log_previous.getDate());
System.out.println(log_previous.getName());
System.out.println(log_previous.getContent());
System.out.println("--------------------------------");
WeeklyLog log_now;
log_now = (WeeklyLog) log_previous.clone();
log_now.setDate("2019年第13周");
System.out.println("****周报****");
System.out.println(log_now.getDate());
System.out.println(log_now.getName());
System.out.println(log_now.getContent());
System.out.println(log_previous);
System.out.println(log_now);
}
}
优点
1.当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,提过新实例的创建效率。
2.扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类卸载配置文件中,增加或减少产品类对原有系统没有任何影响。
3.提供了简化的创建结构,无需专门的工厂类来创建产品。
4.可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份将其状态保存起来,以便在需要的时候使用,可以辅助实现撤销操作。
缺点
1.需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时需要修改源代码,违背了开闭原则。
2.在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类必须支持深克隆,实现起来比较麻烦。