本篇內(nèi)容介紹了“Java原型設(shè)計(jì)模式是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比文登網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式文登網(wǎng)站制作公司更省心,省錢(qián),快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋文登地區(qū)。費(fèi)用合理售后完善,十多年實(shí)體公司更值得信賴。
原型模式
1、原型模式(Prototype模式)是指:用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過(guò)拷貝這些原型,創(chuàng)建新的對(duì)象(復(fù)制,粘貼,克隆的意思,盡量避免new的方式)
2、原型模式是一種創(chuàng)建型設(shè)計(jì)模式,允許一個(gè)對(duì)象再創(chuàng)建另外一個(gè)可定制的對(duì)象,無(wú)需知道如何創(chuàng)建的細(xì)節(jié)
3、工作原理是:通過(guò)將一個(gè)原型對(duì)象傳給那個(gè)要發(fā)動(dòng)創(chuàng)建的對(duì)象,這個(gè)要發(fā)動(dòng)創(chuàng)建的對(duì)象通過(guò)請(qǐng)求原型對(duì)象拷貝它們自己來(lái)實(shí)施創(chuàng)建,即 對(duì)象.clone()
這個(gè)原型模式我是想了一天,都沒(méi)有想到實(shí)際開(kāi)發(fā)怎么能用到它,看了很多博客說(shuō)是Spring創(chuàng)建bean的時(shí)候能用到它,在看源碼的時(shí)候,好多注解式框架就可以看到
怎么實(shí)現(xiàn)原型模式呢?
1、Prototype : 原型類,聲明一個(gè)克隆自己的接口
2、ConcretePrototype: 具體的原型類, 實(shí)現(xiàn) Cloneable 接口,實(shí)現(xiàn)克隆操作,在 JAVA 繼承 Cloneable,重寫(xiě) clone(),實(shí)現(xiàn)一個(gè)克隆自己的操作
3、Client: 讓一個(gè)原型對(duì)象克隆自己,從而創(chuàng)建一個(gè)新的對(duì)象(屬性一樣)
原型模式:淺拷貝和深拷貝
1、對(duì)于數(shù)據(jù)類型是基本數(shù)據(jù)類型的成員變量,淺拷貝會(huì)直接進(jìn)行值傳遞,也就是將該屬性值復(fù)制一份給新的對(duì)象。
2、對(duì)于數(shù)據(jù)類型是引用數(shù)據(jù)類型的成員變量,比如說(shuō)成員變量是某個(gè)數(shù)組、某個(gè)類的對(duì)象等,那么淺拷貝會(huì)進(jìn)行引用傳遞,也就是只是將該成員變量的引用值(內(nèi)存地址)復(fù)制一份給新的對(duì)象。因?yàn)閷?shí)際上兩個(gè)對(duì)象的該成員變量都指向同一個(gè)實(shí)例。在這種情況下,在一個(gè)對(duì)象中修改該成員變量會(huì)影響到另一個(gè)對(duì)象的該成員變量值,從而達(dá)不到我們的需求
舉個(gè)例子
諸葛上學(xué)的時(shí)候絕對(duì)是個(gè)學(xué)渣:每天都不寫(xiě)作業(yè),每天早讀下來(lái)老師都要檢查作業(yè),所以諸葛從來(lái)早讀不讀書(shū),和班花班長(zhǎng)學(xué)習(xí)委員關(guān)系搞好,每天都來(lái)抄他們的作業(yè),完成一個(gè)復(fù)制的過(guò)程,那么問(wèn)題來(lái)了,每個(gè)班不止有一個(gè)學(xué)渣,學(xué)渣有那種憨憨學(xué)渣和聰明學(xué)渣,而諸葛就是那種聰明點(diǎn)的學(xué)渣
憨憨學(xué)渣:抄作業(yè)不管三七二十一,拿著就抄,等老師檢查的時(shí)候,老師就會(huì)發(fā)現(xiàn)這叼毛玩意的作業(yè)怎么和班花的作業(yè)一樣,不用想了,在老師眼里,肯定是憨憨學(xué)渣抄別人的(淺拷貝)
聰明一點(diǎn)的學(xué)渣:抄作業(yè)要有竅門(mén),不能讓老師發(fā)現(xiàn),就做點(diǎn)手腳,答案是一樣的都是同一個(gè)對(duì)象,過(guò)程稍微改點(diǎn),一種題的解法是有很多種方法的(深拷貝)
使用淺拷貝完成創(chuàng)建對(duì)象(實(shí)際開(kāi)發(fā)肯定不要用)
創(chuàng)建一個(gè)對(duì)象
public class Sheep implements Cloneable { private String name; private int age; private String color; private String address = "蒙古羊"; public Sheep friend; //是對(duì)象, 克隆是會(huì)如何處理 public Sheep(String name, int age, String color) { super(); this.name = name; this.age = age; this.color = color; } 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 String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]"; } //克隆該實(shí)例,使用默認(rèn)的clone方法來(lái)完成 @Override protected Object clone() { Sheep sheep = null; try { sheep = (Sheep)super.clone(); } catch (Exception e) { System.out.println(e.getMessage()); } return sheep; } }
測(cè)試淺拷貝
public class Client { public static void main(String[] args) { System.out.println("原型模式完成對(duì)象的創(chuàng)建"); // TODO Auto-generated method stub Sheep sheep = new Sheep("tom", 1, "白色"); sheep.friend = new Sheep("jack", 2, "黑色"); // 更新一個(gè)屬性,發(fā)現(xiàn)復(fù)制克隆的對(duì)象屬性都變了 sheep.setAge(2); Sheep sheep2 = (Sheep)sheep.clone(); //克隆 Sheep sheep3 = (Sheep)sheep.clone(); //克隆 Sheep sheep4 = (Sheep)sheep.clone(); //克隆 Sheep sheep5 = (Sheep)sheep.clone(); //克隆 System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode()); System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode()); System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode()); System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode()); } }
輸出
原型模式完成對(duì)象的創(chuàng)建 sheep2 =Sheep [name=tom, age=2, color=白色, address=蒙古羊]sheep2.friend=312714112 sheep3 =Sheep [name=tom, age=2, color=白色, address=蒙古羊]sheep3.friend=312714112 sheep4 =Sheep [name=tom, age=2, color=白色, address=蒙古羊]sheep4.friend=312714112 sheep5 =Sheep [name=tom, age=2, color=白色, address=蒙古羊]sheep5.friend=312714112 這種方式隨意一個(gè)對(duì)象更改屬性,其他克隆的對(duì)象的屬性都將改變
使用深拷貝完成創(chuàng)建對(duì)象
1、復(fù)制對(duì)象的所有基本數(shù)據(jù)類型的成員變量值
2、為所有引用數(shù)據(jù)類型的成員變量申請(qǐng)存儲(chǔ)空間,并復(fù)制每個(gè)引用數(shù)據(jù)類型成員變量所引用的對(duì)象,直到該對(duì)象可達(dá)的所有對(duì)象。也就是說(shuō),對(duì)象進(jìn)行深拷貝要對(duì)整個(gè)對(duì)象進(jìn)行拷貝
3、深拷貝實(shí)現(xiàn)方式
1:重寫(xiě)clone方法來(lái)實(shí)現(xiàn)深拷貝
2:通過(guò)對(duì)象序列化實(shí)現(xiàn)深拷貝(推薦)
創(chuàng)建一個(gè)對(duì)象
public class DeepProtoType implements Serializable, Cloneable{ /** * @Fields serialVersionUID : TODO(描述) * @author wangmeng * @date 2021年5月13日 */ private static final long serialVersionUID = 1L; public String name; //String 屬性 public DeepCloneableTarget deepCloneableTarget;// 引用類型 public DeepProtoType() { super(); } //深拷貝 - 方式 1 使用clone 方法 @Override protected Object clone() throws CloneNotSupportedException { Object deep = null; //這里完成對(duì)基本數(shù)據(jù)類型(屬性)和String的克隆 deep = super.clone(); //對(duì)引用類型的屬性,進(jìn)行單獨(dú)處理 DeepProtoType deepProtoType = (DeepProtoType)deep; deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone(); // TODO Auto-generated method stub return deepProtoType; } //深拷貝 - 方式2 通過(guò)對(duì)象的序列化實(shí)現(xiàn) (推薦) public Object deepClone() { //創(chuàng)建流對(duì)象 ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; try { //序列化 bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(this); //當(dāng)前這個(gè)對(duì)象以對(duì)象流的方式輸出 //反序列化 bis = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bis); DeepProtoType copyObj = (DeepProtoType)ois.readObject(); return copyObj; } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return null; } finally { //關(guān)閉流 try { bos.close(); oos.close(); bis.close(); ois.close(); } catch (Exception e2) { // TODO: handle exception System.out.println(e2.getMessage()); } } } } public class DeepCloneableTarget implements Serializable, Cloneable { /** * */ private static final long serialVersionUID = 1L; private String cloneName; private String cloneClass; //構(gòu)造器 public DeepCloneableTarget(String cloneName, String cloneClass) { this.cloneName = cloneName; this.cloneClass = cloneClass; } //因?yàn)樵擃惖膶傩?,都是String , 因此我們這里使用默認(rèn)的clone完成即可 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
測(cè)試
public class Client { public static void main(String[] args) throws Exception { DeepProtoType p = new DeepProtoType(); p.name = "諸葛孔暗"; p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛"); //方式1 完成深拷貝 DeepProtoType p2 = (DeepProtoType) p.clone(); p2.name="wangmeng"; System.out.println("p.name=" + p.name + " p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode()); System.out.println("p2.name=" + p2.name + " p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode()); //方式2 完成深拷貝 DeepProtoType p3 = (DeepProtoType) p.deepClone(); p3.name="zhugekongan"; System.out.println("p3.name=" + p3.name + " p3.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode()); } }
輸出:
p.name=諸葛孔暗 p.deepCloneableTarget=705927765 p2.name=wangmeng p2.deepCloneableTarget=366712642 p3.name=zhugekongan p3.deepCloneableTarget=356573597 從而達(dá)到我們的復(fù)制對(duì)象并改變對(duì)象屬性的需求
總結(jié)原型模式的注意事項(xiàng)和細(xì)節(jié)
1、創(chuàng)建新的對(duì)象比較復(fù)雜時(shí),可以利用原型模式簡(jiǎn)化對(duì)象的創(chuàng)建過(guò)程,同時(shí)也能夠提高效率
2、不用重新初始化對(duì)象,而是動(dòng)態(tài)地獲得對(duì)象運(yùn)行時(shí)的狀態(tài)3) 如果原始對(duì)象發(fā)生變化(增加或者減少屬性),其它克隆對(duì)象的也會(huì)發(fā)生相應(yīng)的變化,無(wú)需修改代碼
4、在實(shí)現(xiàn)深克隆的時(shí)候可能需要比較復(fù)雜的代碼
5、缺點(diǎn):需要為每一個(gè)類配備一個(gè)克隆方法,這對(duì)全新的類來(lái)說(shuō)不是很難,但對(duì)已有的類進(jìn)行改造時(shí),需要修改其源代碼,違背了ocp原則,這點(diǎn)請(qǐng)同學(xué)們注意.
“Java原型設(shè)計(jì)模式是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!