好似你,餅印咁:原型模式、淺拷貝與深拷貝
0x01:原型模式簡介
用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。大概意思就是:允許一個對象再創(chuàng)建另外一個可定制的對象,根本無需知道對象創(chuàng)建的細(xì)節(jié)。其工作原理是通過將一個原型對象傳給那個要發(fā)動創(chuàng)建的對象,這個要發(fā)動創(chuàng)建的對象通過請求原型對象拷貝它們自己來實施創(chuàng)建。其UML類圖如下:

主要角色如下:
Prototype:為原型類,聲明一個克隆自身的接口;
ConcretePrototype:為具體實現(xiàn)類,實現(xiàn)一個克隆自身的操作;
Client(客戶端)只需讓一個原型克隆自身,就可以創(chuàng)建一個新的對象。
原型模式主要用于對象的拷貝,其核心是就是類圖中的原型類Prototype,其一般是一個java抽象類或是一個接口,定義了具體原型類所需要的實現(xiàn)的方法。
0x02:原型模式的實現(xiàn)
原型類Prototype
public?abstract?class?Prototype?{
????private?String?name;
????private?String?sex;
????public?Prototype()?{
????}
????public?Prototype(String?name,?String?sex)?{
????????super();
????????this.name?=?name;
????????this.sex?=?sex;
????}
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?String?getSex()?{
????????return?sex;
????}
????public?void?setSex(String?sex)?{
????????this.sex?=?sex;
????}
????//聲明一個實現(xiàn)克隆自身的方法
????public?abstract?Prototype?clone();
}
具體實現(xiàn)類ConcretePrototype
public?class?ConcretePrototype?extends?Prototype{
????public?ConcretePrototype(String?name,?String?sex)?{
????????super(name,?sex);
????}
????@Override
????public?ConcretePrototype?clone()?{
????????return?new?ConcretePrototype(this.getName(),?this.getSex());
????}
}
原型模式測試代碼
public?class?Client?{
????public?static?void?main(String[]?args)?{
????????ConcretePrototype?p?=?new?ConcretePrototype("Hello",?"gril");
????????ConcretePrototype?c?=?(ConcretePrototype)?p.clone();
????????System.out.println(c.getName()?+?",?"?+?c.getSex());
????}
}
0x03:JDK中淺拷貝、深拷貝與原型模型
Java賦值是復(fù)制對象引用,如果想要得到一個對象的副本,使用賦值操作是無法達到目的的
普通pojo對象Person
public?class?Person?{
????private?String?name;
????private?int?age;
?????//省略getter ?setter}
測試代碼
public?static?void?main(String[]?args)?{
??????Person?p1?=?new?Person();
??????p1.setAge(31);
??????p1.setName("java樂園");
??????Person?p2?=?p1;
??????System.out.println(p1==p2);//?true
}
如果創(chuàng)建一個對象的新的副本,也就是說他們的初始狀態(tài)完全一樣,但以后可以改變各自的狀態(tài),而互不影響,就需要用到Java中對象的復(fù)制,如原生的clone()方法。如何進行對象克隆呢?
Object對象有個clone()方法,實現(xiàn)了對象中各個屬性的復(fù)制,但它的可見范圍是protected的,所以實體類使用克隆的前提是:
實現(xiàn)Cloneable接口,這是一個標(biāo)記接口,自身沒有任何方法;?
覆蓋clone()方法,可見性提升為public;
public?class?Person?implements?Cloneable{
????private?String?name;
????private?int?age;
?????//省略getter ?setter
????@Override
????protected?Object?clone()?throws?CloneNotSupportedException?{
????????return?super.clone();
????}
}
測試代碼
public?static?void?main(String[]?args)?throws?Exception{
????????Person?p1=new?Person();
??????????p1.setAge(31);
??????????p1.setName("java樂園");
??????????Person?p2=(Person)?p1.clone();
??????????System.out.println(p1?==?p2);//false
??????????p2.setName("架構(gòu)師知音");
??????????System.out.println("p1?=?"?+?p1.getName()?+?",?"?+?p1.getAge());?//?p1?=?java樂園,?31
??????????System.out.println("p2?=?"?+?p2.getName()?+?",?"?+?p2.getAge());?//p2?=?架構(gòu)師知音,?31
????}
該測試用例只有兩個基本類型的成員變量,測試目的達到。好像沒有任何問題?為Person增加一個地址的引用類型成員變量Address
public?class?Address?{
????private?String?city;
????private?String?street;
????//省略getter setter
}
Person增加Address成員對象
public?class?Person?implements?Cloneable{
????private?String?name;
????private?int?age;
????private?Address?address;//省略 getter setter
????@Override
????protected?Object?clone()?throws?CloneNotSupportedException?{
????????return?super.clone();
????}
}
測試代碼
public?static?void?main(String[]?args)?throws?Exception{
??????????Address?address=new?Address();
??????????address.setStreet("天庭88號");
??????????address.setCity("魔都");
??????????Person?p1=new?Person();
??????????p1.setAge(31);
??????????p1.setName("java樂園");
??????????p1.setAddress(address);
??????????Person?p2=(Person)?p1.clone();
??????????System.out.println(p1?==?p2);?//false
??????????p2.getAddress().setCity("廣東");
??????????System.out.println("p1="?+?p1.getAddress().getCity());
??????????System.out.println("p2="+??p2.getAddress().getCity());
????}
遇到了麻煩,只修改了p2的城市,兩個地址城市都變成了“廣東”。這個實例是淺拷貝和深拷貝的典型用例。
淺拷貝:被復(fù)制對象的所有值屬性都含有與原來對象的相同,而所有的對象引用屬性仍然指向原來的對象。
深拷貝:在淺拷貝的基礎(chǔ)上,所有引用其他對象的變量也進行了clone,并指向被復(fù)制過的新對象。
也就是說,一個默認(rèn)的clone()方法實現(xiàn)機制,仍然是賦值。
如果一個被復(fù)制的屬性都是基本類型,那么只需要實現(xiàn)當(dāng)前類的cloneable機制就可以了,此為淺拷貝;如果被復(fù)制對象的屬性包含其他實體類對象引用,那么這些實體類對象都需要實現(xiàn)Cloneable接口并覆蓋clone()方法。對Address做以下修改:
public?class?Address?implements?Cloneable?{
????private?String?city;
????private?String?street;
????//省略?getter??setter
????@Override
????protected?Object?clone()?throws?CloneNotSupportedException?{
????????return?super.clone();
????}
}
通過以上案例可以看出通過Cloneable接口并覆蓋Object類的clone()方法就很方便的實現(xiàn)了原型模式。
參考:https://www.cnblogs.com/xuanxufeng/p/6558330.html
喜歡,在看
