原型模式也屬于創(chuàng)造型設(shè)計模式玄柠,他是通過復(fù)制一個已經(jīng)存在的對象實例而得到一個新的實例,避免繁瑣的實例化過程霎苗。在這里被復(fù)制的對象實例叫做原型争剿,復(fù)制原型也叫克隆對象已艰,有深克隆和淺克隆兩種。
淺克隆
對值類型的成員變量進(jìn)行值的復(fù)制,對引用類型的成員變量只復(fù)制引用,不復(fù)制引用的對象蚕苇;也就是值類型和引用進(jìn)行復(fù)制
深克隆
在淺克隆的基礎(chǔ)上哩掺,對引用類型也進(jìn)行克隆,而不僅僅是引用
原型克隆的 UML 類圖如下:
client:提出創(chuàng)建對象請求涩笤;
propotype:抽象原型嚼吞,給出所有具體原型需要實現(xiàn)的接口;
concretePropotype:具體的原型對象蹬碧,需要被復(fù)制的對象舱禽;
仍然加以代碼實現(xiàn)
先來淺拷貝,抽象原型
public interface Prototype extends Cloneable {
public Object clone() ;
}
//具體克隆對象
public class ConcretePropotype implements Propotype {
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
客戶端測試下
public class Client {
public static void main(String[] args) {
ConcretePropotype propotype=new ConcretePropotype();
propotype.setName("zhangsan");
propotype.setAge(11);
ConcretePropotype propotypeClone=(ConcretePropotype) propotype.clone();
System.out.println(propotypeClone.getName());
propotypeClone.setName("lisi");
propotypeClone.setAge(12);
System.out.println(propotype.getAge());
System.out.println(propotypeClone.getName());
}
}
這個屬于淺克隆,沒有涉及到引用類型恩沽,為了驗證下誊稚,繼續(xù)引入一個對象Student
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
這里具體原型對象增加引入,代碼為:
public class ConcretePropotype2 implements Propotype {
private String name;
private int age;
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
進(jìn)入 Client 端進(jìn)行驗證一下
public class Client2 {
public static void main(String[] args) {
ConcretePropotype2 propotype=new ConcretePropotype2();
Student stu=new Student();
stu.setAge(50);
stu.setName("東郭");
propotype.setStudent(stu);
ConcretePropotype2 propotypeClone=(ConcretePropotype2) propotype.clone();
propotypeClone.getStudent().setName("西施");
propotypeClone.getStudent().setAge(100);
System.out.println("原型:"+propotype.getStudent().getName());
System.out.println("克隆后:"+propotypeClone. getStudent().getName());
System.out.println("原型:"+propotype.getStudent().getAge());
System.out.println("克隆后:"+propotypeClone. getStudent().getAge());
}
}
由于是淺克隆飒筑,只是引用復(fù)制了片吊,所以克隆后把原來的對象也修改了绽昏,最后的結(jié)果是
原型:西施
克隆后:西施
原型:100
克隆后:100
這個情況就會出現(xiàn)很大問題协屡,把原來的對象徹底修改了,這可是不想遇到的全谤,此時肤晓,深克隆粉墨登場,來解決這個問題认然;但是為了深克隆补憾,需要克隆的對象可序列化,之前的Student
對象需要實現(xiàn)public class Student implements Serializable
卷员,這樣在 clone 對象里面利用串行化來做深復(fù)制盈匾。
public Object deepClone(){
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
//將對象從流里面讀出來
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
當(dāng)然還可以逐個對象的引用進(jìn)行復(fù)制,那樣引用層次較淺還可以接受毕骡,太深的話操作性非常不好削饵。還是建議利用串行化來做深復(fù)制
岩瘦。
深度克隆之后完全就是兩個對象了,互相不干擾窿撬,但需要克隆的對象序列化启昧。既然是從克隆出來的,所以依附就小多了劈伴,只要產(chǎn)品具有克隆方法就可以克隆一個新的自己出來密末,再加以演化,就可以很方便的造出不同級別的產(chǎn)品出來跛璧。唯一的難點就是何時何地增加克隆方法严里,以及不能克隆的屬性加以transient
標(biāo)識。