原型模式(浅克隆与深克隆)
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不变。