原型模式分三个角色:抽象原型类,具体原型类,客户类。
抽象原型类(prototype):它是声明克隆方法的接口,是所有具体原型类的公共父类,它可以是接口,抽象类甚至是一个具体的实现类。
具体原型类(concretePrototype):它实现了抽象原型类中声明的克隆方法,在克隆方法中返回一个自己的克隆对象。
客户类(Client):在客户类中,使用原型对象只需要通过工厂方式创建或者直接NEW(实例化一个)原型对象,然后通过原型对象的克隆方法就能获得多个相同的对象。由于客户端是针对抽象原型对象编程的所以还可以可以很方便的换成不同类型的原型对象!
浅克隆
在浅克隆中,如果原型对象的成员变量是值类型(八大基本类型,byte,short,int,long,char,double,float,boolean).那么就直接复制,如果是复杂的类型,(枚举,String,对象)就只复制对应的内存地址。
深克隆
深克隆,就是全部复制,然后各自独立。
原型模式的实现
附件类:
public class Attachment {
private String name; //附件名
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void download() {
System.out.println("下载附件"+name);
}
}
周报类:这里面很多属性其实可以忽略,但是再真正的操作时他们是确实存在的! 关键点在于,实现cloneable接口以及用object的clone方法。
public class WeeklyLog implements Cloneable{
private Attachment attachment;
private String date;
private String name;
private String content;
public Attachment getAttachment() {
return attachment;
}
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
//实现clone()方法实现浅克隆
public WeeklyLog clone() {
//需要实现cloneable的接口,直接继承object就好,它里面自带一个clone方法!
Object obj = null;
try {
obj = super.clone();
return (WeeklyLog)obj;
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
System.out.println("不支持克隆方法!");
return null;
}
}
}
public class Client {
//测试类,客户端
public static void main(String[] args) {
WeeklyLog log_1,log_2;
log_1 = new WeeklyLog(); //创建原型对象
Attachment attachment = new Attachment(); //创建附件对象
log_1.setAttachment(attachment); //将附件添加到周报种去
log_2=log_1.clone(); //克隆周报
System.out.println("周报是否相同"+(log_1==log_2));
System.out.println("附件是否相同"+(log_1.getAttachment()==log_2.getAttachment()));
}
}
深克隆
附件类:将其序列化
import java.io.Serializable;
/**
*
* <p>Title: Attachment</p>
* <p>Description:附件类 </p>
* @author HAND_WEILI
* @date 2018年9月2日
*/
public class Attachment_2 implements Serializable {
private String name; //附件名
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void download() {
System.out.println("下载附件"+name);
}
}
周报类
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
/**
*
* <p>Title: WeeklyLog</p>
* <p>Description:周报类充当具体的原型类 </p>
* @author HAND_WEILI
* @date 2018年9月2日
*/
public class WeeklyLog_2 implements Serializable{
private Attachment_2 attachment;
private String date;
private String name;
private String content;
public Attachment_2 getAttachment() {
return attachment;
}
public void setAttachment(Attachment_2 attachment) {
this.attachment = attachment;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
//通过序列化进行深克隆
public WeeklyLog_2 deepclone() throws Exception {
//将对象写入流中,
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象取出来
ByteArrayInputStream bi = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bi);
return (WeeklyLog_2)ois.readObject();
}
}
客户类
public class Client_2 {
//测试类,客户端
public static void main(String[] args) {
WeeklyLog_2 log_1,log_2=null;
log_1 = new WeeklyLog_2(); //创建原型对象
Attachment_2 attachment = new Attachment_2(); //创建附件对象
log_1.setAttachment(attachment); //将附件添加到周报种去
try {
log_2=log_1.deepclone();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //克隆周报
System.out.println("周报对象是否相同"+(log_1==log_2));
System.out.println("附件对象是否相同"+(log_1.getAttachment()==log_2.getAttachment()));
}
}