一、简介
原型模式是对一个对象的进行克隆,例如我们在写论文的时候,做课程设计的时候,不喜欢做报告,在网上查找到相应的资料,ctrl+c和ctrl+v完成复制粘贴,减少了工作量。原型模式也是实现了相应的功能。
原型模式的工作原理很简单:将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。由于在软件系统中我们经常会遇到需要创建多个相同或者相似对象的情况,因此原型模式在真实开发中的使用频率还是非常高的。原型模式是一种“另类”的创建型模式,创建克隆对象的工厂就是原型类自身,工厂方法由克隆方法来实现。
二、具体事例
接下来我们就用代码来说话,代码时最友好的交流工具,我们首先谈一个具体的实例
例如一家公司需要实现工作报表,可能下周的工作报表与上周的工作报表类似,因此我们就有必要完成原型模式进行设计。
我们需要继承与cloneable接口
package prototype;
class WeeklyLog implements Cloneable{
private String name;
private String date;
private String content;
private Attachment attachment;
public Attachment getAttachment() {
return attachment;
}
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
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;
}
public Object clone()
{
Object obj = null;
try
{
obj = super.clone();
return (WeeklyLog)obj;
}
catch(CloneNotSupportedException e)
{
System.out.println("不支持复制!");
return null;
}
}
}
在该类中,我们实现了clone方法,该方法为Java中自带的方法,我们只需要继承于他就好了
。
private static void display1() {
WeeklyLog pre_Log = new WeeklyLog();
pre_Log.setName("张三");
pre_Log.setDate("第十二周");
pre_Log.setContent("工作周报");
System.out.println("周报");
System.out.println(pre_Log.getName());
System.out.println(pre_Log.getDate());
System.out.println(pre_Log.getContent());
WeeklyLog new_Log;
new_Log = (WeeklyLog) pre_Log.clone();
System.out.println(new_Log.getName());
System.out.println(new_Log.getDate());
System.out.println(new_Log.getContent());
}
以上我们实现的浅层克隆,那什么是浅层克隆呢, 在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制
接下来我们再了解一下深层克隆
在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制
我们设计了一个引用类型的报表类,该类在clone方法中为引用类型的
package prototype;
import java.io.Serializable;
public class Attachment implements Serializable{
private String filename;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public void download(){
System.out.println("下载的文件名字为"+filename);
}
}
接下里让我们一起看核心代码,深层可控
package prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepWeeklyLog implements Serializable {
private String name;
private String date;
private String content;
private Attachment attachment;
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;
}
public Attachment getAttachment() {
return attachment;
}
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
public DeepWeeklyLog deepclone() throws IOException, ClassNotFoundException{
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(this);
ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return (DeepWeeklyLog)ois.readObject();
}
}
原型模式的优点及适用场景
使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。
因为以上优点,所以在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。