原型模式(淺克隆與深克隆)
1.定義:
原型模式是一種物件建立型模式,用原型例項指定建立物件的種類,並且通過複製這些原型建立新的物件。原型模式允許一個物件在建立另一個一個可定製物件,無需指導建立細節。
2.原型模式的實現:
為了獲取物件的一份拷貝,我們可以利用Object類的clone()方法,具體步驟如下:
(1)在派生類中覆蓋基類的clone()方法,並宣告為public;
(2)在派生類的clone方法中,呼叫super.clone();
(3)在派生類中實現Cloneable介面
注意:一個類包含一些成員物件,在使用原型模式克隆物件時,根據其成員物件是否也克隆,原型模式可分為兩種形式,淺克隆和深克隆。
2.1淺克隆
在淺克隆中,被複制物件的所有普通成員變數都具有與原來物件相同的值,而所有的對其他物件的引用仍然指向原來的物件。也就是說,淺克隆僅僅複製所考慮的物件,不會複製它所引用的成員物件。
案例:設計一個客戶類Customer,其中客戶地址儲存在地質類Address中,用淺克隆和深克隆分別實現Customer物件的複製。
淺克隆示意圖
地址類:Address
public class Address { private String country; private String province; private String city; public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Address(String country, String province, String city) { super(); this.country = country; this.province = province; this.city = city; } @Override public String toString() { return "Address [city=" + city + ", country=" + country + ", province=" + province + "]"; } }
客戶類:
public class Customer implements Cloneable{ private String name; private Address address; public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Customer(String name, Address address) { super(); this.name = name; this.address = address; } @Override public String toString() { return "Customer [address=" + address + ", name=" + name + "]"; } public Customer clone(){ Customer clone=null; try { clone=(Customer) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return clone; } }
測試類:
package page133_2;
public class Test {
public static void main(String[] args) {
Address address=new Address("SC","CD","WHQ");
Customer c1=new Customer("sqq", address);
Customer c2=c1.clone();
c2.getAddress().setCity("MY");
System.out.println("c1"+c1.toString());
System.out.println("c2"+c2.toString());
}
}
2.2深克隆
在深克隆中被複制的物件的所有普通成員變數也都含有與原來的物件相同的值,出去那些引用其他物件的變數。換言之,在深克隆中,除了物件本身被複制外,物件包含的引用也被複制,也就是其中的成員物件也被複制。
深克隆示意圖
案例:對以上程式碼做如下修改:
1.針對Address類:
(1)在Address中重寫clone()方法,並宣告為public;
(2)在Address的clone方法中,呼叫super.clone();
(3)在Address中實現Cloneable介面;
2.針對Customer類:呼叫Address類的clone()方法修改為:
public Customer clone(){
Customer cus=null;
try {
cus=(Customer) super.clone();
cus.address=(Address) address.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return cus;
}
3.測試類不變。
附:也可以採用序列化的方式實現深克隆。
在JAVA語言中,序列化(Serialization)就是將物件寫到流的過程,寫到流中的物件是原有的物件的一個拷貝,而原物件仍存在記憶體中。通過序列化實現的拷貝不僅可以複製物件本身,而且也可以複製其引用的成員物件,因此通過序列化將物件寫入一個流中,再從流中將其讀出來,從而實現深克隆。
要做的修改如下:
1.Address類實現Serializable介面
2.Customer類中的修改如下:
public class Customer implements Serializable{
private Address address;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Customer(String name, Address address) {
super();
this.name = name;
this.address = address;
}
@Override
public String toString() {
return "Customer [address=" + address + ", name=" + name + "]";
}
public Object deepClone() throws Exception {
//將物件寫入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bao);
oos.writeObject(this);
//將物件從流中取出
ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return(ois.readObject());
}
}
3.測試類Test不變。