JAVA設計模式 2【建立型】原型模式的理解與使用、理解淺克隆和深克隆

程式猿小碼發表於2020-06-21

在本節中,我們將學習和使用原型模式;這一節學習的原型模式也是建立型 模式的其中之一。再次複習一下:建立型 模式就是描述如何去更好的建立一個物件。

我們都知道,在JAVA 語言中。使用new 關鍵字建立一個新物件。將新的物件放到堆記憶體 裡面。當然,這個記憶體肯定是有大小限制的,況且,JAVA 不同於C語言等。 有記憶體管理機制,就是我們常說的垃圾回收器GC,才可以保證記憶體不被溢位。

說這些其實就是為了表示:為啥要用單例模式,能節省記憶體的時候,能用一個物件解決重複的事情,絕對不會建立多個。

概述

原型模式描述的如何快速建立重複的物件,並且減少new 關鍵字的使用。

  • 抽象原型類
  • 具體原型類
  • 訪問類

容我來一個一個解釋:

抽象原型類 也就是我們具體要實現的某個類,這個類在JAVA 裡面是有具體的介面的,其實是一個空介面,Cloneable

 * @author  unascribed
 * @see     java.lang.CloneNotSupportedException
 * @see     java.lang.Object#clone()
 * @since   JDK1.0
 */
public interface Cloneable {
}

我們會發現,這個類沒有任何的方法,怎麼來實現它,不要慌。先接著走。

具體原型類 也就是我們具體要克隆 的物件。比如我們重複的要建立100個學生Student 物件,那麼具體的學生物件就是具體原型類

public class Student implements Cloneable {

    private int id;

    private String name;

    private int sex;
}

訪問類 我就不必多說了

淺克隆和深克隆

原型模式其實也分淺克隆和深克隆。如何理解這兩個概念呢?

淺克隆

protected native Object clone() throws CloneNotSupportedException;

淺克隆,只需要具體原型類 實現Cloneable 介面,並且重寫父類Object類的clone() 方法,即可實現物件的淺克隆。

Student student1 = new Student(1, "李四");
Student student2 = student1.clone();

System.out.println(student1);
System.out.println(student2);

System.out.println(student1 == student2);
---------------------
學號:1,姓名:李四
學號:1,姓名:李四
false
  • 通過執行clone() 方法即可建立一個相同的,具有同樣屬性的物件。
  • 並且是新的物件,記憶體地址有所不同。

我們來看看,對於引用型別的變數,淺克隆是否可以進行克隆;

Teacher teacher = new Teacher(1, "張老師");

Student student1 = new Student(1, "李四", teacher);
Student student2 = student1.clone();

System.out.println(student1);
System.out.println(student2);

System.out.println(student1 == student2);
------------
學號:1,姓名:李四,老師=Teacher@1b6d3586
學號:1,姓名:李四,老師=Teacher@1b6d3586
false

我們發現,引用型別並沒有被克隆,也就是說:

特點

  • 淺克隆對於基本型別,可以進行完全的克隆,並且克隆的物件是一個新的物件
  • 但是物件裡面的引用,是無法被克隆的。

深克隆(序列化)

何謂序列化?

我們建立的都是儲存在記憶體裡面的,只要被虛擬機器GC進行回收,那麼這個物件的任何屬性都是消失,我們能不能找一個方法,將記憶體中這種物件的屬性以及物件的狀態通過某種東西儲存下來,比如儲存到資料庫,下次從資料庫將這個物件還原到記憶體裡面。 這就是序列化。

  • 序列化 記憶體物件->序列字元
  • 反序列化 序列字元->記憶體物件

請參考: https://baike.baidu.com/item/序列化/2890184

JAVA 序列化

 * @see java.io.Externalizable
 * @since   JDK1.1
 */
public interface Serializable {
}

JAVA 提供了一個空介面,其實這個介面和上面的Cloneable 一樣,都是一個空介面,其實這個空介面就是作為一種標識 你的物件實現了這個介面,JAVA 認為你的這個就可以被序列化 ,就是這麼簡單。

Teacher teacher = new Teacher(1, "張老師");

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(outputStream);

stream.writeObject(teacher);
System.out.println(Arrays.toString(outputStream.toByteArray()));
----------
[-84, -19, 0, 5, 115, 114, 0, 7, 84, 101, 97,。。。。。。

通過將物件序列化、其實也就是將記憶體中的物件轉化為二進位制 位元組陣列

反序列化

Teacher teacher = new Teacher(1, "張老師");
System.out.println(teacher);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(outputStream);

stream.writeObject(teacher);
System.out.println(Arrays.toString(outputStream.toByteArray()));

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream);

Teacher teacher1 = (Teacher) inputStream.readObject();
System.out.println(teacher1);
---------------
id=1,name=張老師
[-84, -19, 0, 5, 115, xxxxx,-127, -27, -72, -120]
id=1,name=張老師

通過序列化和反序列化,即可物件的深克隆

小結

這一節,在講述 原型模式的同時,將原有實現原型模式的clone() 淺克隆,延伸到深克隆這一概念。其實JAVA 的原型模式,實現起來較為簡單。但還是要按需要實現,Object 類提供的 clone 淺克隆 是沒辦法克隆物件的引用型別的。需要克隆引用型別,還是需要序列化 深克隆

參考

http://c.biancheng.net/view/1343.html
https://www.liaoxuefeng.com/wiki/1252599548343744/1298366845681698

程式碼示例

https://gitee.com/mrc1999/Dev-Examples

歡迎關注

相關文章