設計模式-Prototype

學習參考:
[url]http://www.cnblogs.com/hegezhou_hot/archive/2010/12/04/1896471.html[/url]

[b]定義:[/b]是一種創建型設計模式,它通過複製一個已經存在的實例來返回新的實例,而不是新建實例.被複制的實例就是我們所稱的原型,這個原型是可定製的.

[b]重點:[/b]
1、原型模式主要用於對象的複製,Prototype模式允許一個對象再創建另外一個可定製的對象,根本無需知道任何如何創建的細節。
2、使用原型模式創建對象比直接new一個對象在性能上要好的多,因爲Object類的clone方法是一個本地方法,它直接操作內存中的二進制流,特別是複製大對象時,性能的差別非常明顯

[b]應用場景:[/b]原型模式多用於創建複雜的或者耗時的實例, 因爲這種情況下,複製一個已經存在的實例可以使程序運行更高效,或者創建值相等,只是命名不一樣的同類數據.


[b]類圖:[/b]

[img]http://dl2.iteye.com/upload/attachment/0120/6291/19c68f7f-ff1d-334e-b498-9cbc8143d028.jpg[/img]


JDK中的體現:
Object.clone;Cloneable

[img]http://hi.csdn.net/attachment/201101/3/0_1294058951u556.gif[/img]



class Prototype implements Cloneable {
public Prototype clone(){
Prototype prototype = null;
try{
prototype = (Prototype)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return prototype;
}
}

class ConcretePrototype extends Prototype{
public void show(){
System.out.println("原型模式實現類");
}
}

public class Client {
public static void main(String[] args){
ConcretePrototype cp = new ConcretePrototype();
ConcretePrototype clonecp = (ConcretePrototype)cp.clone();
clonecp.show();
}
}


輸出:
原型模式實現類

[b]擴展:[/b]
[b]1、clone方法構造的對象是沒有調用構造方法的[/b]

class Prototype implements Cloneable {
public Prototype clone() {
Prototype prototype = null;
try {
prototype = (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return prototype;
}
}

class ConcretePrototype extends Prototype {
private static int i = 0;

public ConcretePrototype() {
i++;
}

public void show() {
System.out.println("原型模式實現類" + i);
}
}

public class Test {
public static void main(String[] args) {
ConcretePrototype cp = new ConcretePrototype();
ConcretePrototype clonecp = (ConcretePrototype) cp.clone();

System.out.println(cp == clonecp);
System.out.println(cp.equals(clonecp));

cp.show();
clonecp.show();
}
}


輸出:
false
false
原型模式實現類1
原型模式實現類1
如果是走了構造方法,clonecp.show();應該輸出2

2、引用只會進行淺拷貝 (prototype 和 clone 的引用實例:是同一個對象)

class P implements Cloneable {
public P clone() {
P prototype = null;
try {
prototype = (P) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return prototype;
}
}

/**
* 引用只會進行淺拷貝,
* @author xinchun.wang
*/
public class A extends P {

private List<String> list = new ArrayList<String>();
private String s = "s";

public static void main(String[] args) {
A a = new A();
A ca = (A)a.clone();
System.out.println(a.equals(ca));//false
System.out.println(a.list == ca.list); //true

a.list.add("aaa");
System.out.println(ca.list); //[aaa]

System.out.println("---------------------------");
System.out.println("a.s: " + a.s);//a.s:s
System.out.println("ca.s: " + ca.s);//ca.s: s
a.s = "b";
System.out.println("a.s: " + a.s);//a.s: b
System.out.println("ca.s: " + ca.s);//ca.s: s

}
}



[b]3、深拷貝與淺拷貝[/b]
Object類的clone方法只會拷貝對象中的基本的數據類型(8種基本數據類型byte,char,short,int,long,float,double,boolean),對於數組、容器對象、引用對象等都不會拷貝,這就是淺拷貝。如果要實現深拷貝,必須將原型模式中的引用對象(數組、容器對象)另行拷貝。

[img]http://dl2.iteye.com/upload/attachment/0120/6305/8025d430-a05a-3c61-bb31-e9ad4f000d89.png[/img]

舉例:

public class Prototype implements Cloneable {
private ArrayList list = new ArrayList();
public Prototype clone(){
Prototype prototype = null;
try{
prototype = (Prototype)super.clone();
prototype.list = (ArrayList) this.list.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return prototype;
}
}

注意:由於ArrayList不是基本類型,所以成員變量list,不會被拷貝,需要我們自己實現深拷貝,幸運的是java提供的大部分的容器類都實現了Cloneable接口。所以實現深拷貝並不是特別困難。
以下是 ArrayList的clone實現,其他引用實現可以參考:

public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}

4、深拷貝的實現舉例:

class P implements Cloneable {
}

/**
* @author xinchun.wang
*/
public class A extends P {
@SuppressWarnings("unchecked")
public A clone() {
A prototype = null;
try {
prototype = (A) super.clone();
prototype.list = (List<String>) ((ArrayList<String>)(this.list)).clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return prototype;
}

private List<String> list = new ArrayList<String>();

public static void main(String[] args) {
A a = new A();
A ca = a.clone();

a.list.add("aaaa");
System.out.println(a.list); //[aaaa]
System.out.println(ca.list);//[]
}
}

還有一種方式:
序列化實現,把對象寫道流裏的過程是串行化(Serilization)過程;把對象從流中讀出來是並行化(Deserialization)過程. 寫在流裏的是對象的一個拷貝,然後再從流裏讀出來重建對象.

public class PrototypeSe implements Serializable {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

public class NewPrototypeSe implements Serializable {

private String id;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

private PrototypeSe prototype;

public PrototypeSe getPrototype() {
return prototype;
}

public void setPrototype(PrototypeSe prototype) {
this.prototype = prototype;
}

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) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}

}

public class TestDeepClone {

public static void main(String[] args) {
// TODO Auto-generated method stub
PrototypeSe po = new PrototypeSe();
po.setName("test1");
NewPrototypeSe se = new NewPrototypeSe();
se.setPrototype(po);

NewPrototypeSe deepClone = (NewPrototypeSe)se.deepClone();
deepClone.getPrototype().setName("test2");

System.out.println("original name:" + se.getPrototype().getName());
System.out.println("cloned name:" + deepClone.getPrototype().getName());

}
}


結果:
original name:test1
cloned name:test2
發佈了60 篇原創文章 · 獲贊 1 · 訪問量 9445
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章