您好,登錄后才能下訂單哦!
本篇內容介紹了“Java原型設計模式是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
原型模式
1、原型模式(Prototype模式)是指:用原型實例指定創建對象的種類,并且通過拷貝這些原型,創建新的對象(復制,粘貼,克隆的意思,盡量避免new的方式)
2、原型模式是一種創建型設計模式,允許一個對象再創建另外一個可定制的對象,無需知道如何創建的細節
3、工作原理是:通過將一個原型對象傳給那個要發動創建的對象,這個要發動創建的對象通過請求原型對象拷貝它們自己來實施創建,即 對象.clone()
這個原型模式我是想了一天,都沒有想到實際開發怎么能用到它,看了很多博客說是Spring創建bean的時候能用到它,在看源碼的時候,好多注解式框架就可以看到
<bean id="" class="" scope="prototype"/>
怎么實現原型模式呢?
1、Prototype : 原型類,聲明一個克隆自己的接口
2、ConcretePrototype: 具體的原型類, 實現 Cloneable 接口,實現克隆操作,在 JAVA 繼承 Cloneable,重寫 clone(),實現一個克隆自己的操作
3、Client: 讓一個原型對象克隆自己,從而創建一個新的對象(屬性一樣)
原型模式:淺拷貝和深拷貝
1、對于數據類型是基本數據類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值復制一份給新的對象。
2、對于數據類型是引用數據類型的成員變量,比如說成員變量是某個數組、某個類的對象等,那么淺拷貝會進行引用傳遞,也就是只是將該成員變量的引用值(內存地址)復制一份給新的對象。因為實際上兩個對象的該成員變量都指向同一個實例。在這種情況下,在一個對象中修改該成員變量會影響到另一個對象的該成員變量值,從而達不到我們的需求
舉個例子
諸葛上學的時候絕對是個學渣:每天都不寫作業,每天早讀下來老師都要檢查作業,所以諸葛從來早讀不讀書,和班花班長學習委員關系搞好,每天都來抄他們的作業,完成一個復制的過程,那么問題來了,每個班不止有一個學渣,學渣有那種憨憨學渣和聰明學渣,而諸葛就是那種聰明點的學渣
憨憨學渣:抄作業不管三七二十一,拿著就抄,等老師檢查的時候,老師就會發現這叼毛玩意的作業怎么和班花的作業一樣,不用想了,在老師眼里,肯定是憨憨學渣抄別人的(淺拷貝)
聰明一點的學渣:抄作業要有竅門,不能讓老師發現,就做點手腳,答案是一樣的都是同一個對象,過程稍微改點,一種題的解法是有很多種方法的(深拷貝)
使用淺拷貝完成創建對象(實際開發肯定不要用)
創建一個對象
public class Sheep implements Cloneable { private String name; private int age; private String color; private String address = "蒙古羊"; public Sheep friend; //是對象, 克隆是會如何處理 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 + "]"; } //克隆該實例,使用默認的clone方法來完成 @Override protected Object clone() { Sheep sheep = null; try { sheep = (Sheep)super.clone(); } catch (Exception e) { System.out.println(e.getMessage()); } return sheep; } }
測試淺拷貝
public class Client { public static void main(String[] args) { System.out.println("原型模式完成對象的創建"); // TODO Auto-generated method stub Sheep sheep = new Sheep("tom", 1, "白色"); sheep.friend = new Sheep("jack", 2, "黑色"); // 更新一個屬性,發現復制克隆的對象屬性都變了 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()); } }
輸出
原型模式完成對象的創建 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 這種方式隨意一個對象更改屬性,其他克隆的對象的屬性都將改變
使用深拷貝完成創建對象
1、復制對象的所有基本數據類型的成員變量值
2、為所有引用數據類型的成員變量申請存儲空間,并復制每個引用數據類型成員變量所引用的對象,直到該對象可達的所有對象。也就是說,對象進行深拷貝要對整個對象進行拷貝
3、深拷貝實現方式
1:重寫clone方法來實現深拷貝
2:通過對象序列化實現深拷貝(推薦)
創建一個對象
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; //這里完成對基本數據類型(屬性)和String的克隆 deep = super.clone(); //對引用類型的屬性,進行單獨處理 DeepProtoType deepProtoType = (DeepProtoType)deep; deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepCloneableTarget.clone(); // TODO Auto-generated method stub return deepProtoType; } //深拷貝 - 方式2 通過對象的序列化實現 (推薦) public Object deepClone() { //創建流對象 ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; try { //序列化 bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(this); //當前這個對象以對象流的方式輸出 //反序列化 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 { //關閉流 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; //構造器 public DeepCloneableTarget(String cloneName, String cloneClass) { this.cloneName = cloneName; this.cloneClass = cloneClass; } //因為該類的屬性,都是String , 因此我們這里使用默認的clone完成即可 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
測試
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 從而達到我們的復制對象并改變對象屬性的需求
總結原型模式的注意事項和細節
1、創建新的對象比較復雜時,可以利用原型模式簡化對象的創建過程,同時也能夠提高效率
2、不用重新初始化對象,而是動態地獲得對象運行時的狀態3) 如果原始對象發生變化(增加或者減少屬性),其它克隆對象的也會發生相應的變化,無需修改代碼
4、在實現深克隆的時候可能需要比較復雜的代碼
5、缺點:需要為每一個類配備一個克隆方法,這對全新的類來說不是很難,但對已有的類進行改造時,需要修改其源代碼,違背了ocp原則,這點請同學們注意.
“Java原型設計模式是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。