設計模式總結篇系列:原型模式(Prototype)

首先對原型模式進行一個簡單概念說明:經過一個已經存在的對象,複製出更多的具備與此對象具備相同類型的新的對象。html

在理解Java原型模式以前,首先須要理解Java中的一個概念:複製/克隆。java

在博文《Java總結篇系列:java.lang.Object》一文中,對Java中的clone()方法進行了必定的闡述。同時,咱們須要知道,Java中的對象複製/克隆分爲淺複製和深複製。設計模式

1、淺複製:函數

咱們知道,一個類的定義中包括屬性和方法。屬性用於表示對象的狀態,方法用於表示對象所具備的行爲。其中,屬性既能夠是Java中基本數據類型,也能夠是引用類型。Java中的淺複製一般使用clone()方式完成。測試

當進淺複製時,clone函數返回的是一個引用,指向的是新的clone出來的對象,此對象與原對象分別佔用不一樣的堆空間。同時,複製出來的對象具備與原對象一致的狀態。ui

此處對象一致的狀態是指:複製出的對象與原對象中的屬性值徹底相等==。this

下面以複製一本書爲例:spa

1.定義Book類和Author類:設計

 1 class Author {  2 
 3     private String name;  4     private int age;  5 
 6     public String getName() {  7         return name;  8  }  9 
10     public void setName(String name) { 11         this.name = name; 12  } 13 
14     public int getAge() { 15         return age; 16  } 17 
18     public void setAge(int age) { 19         this.age = age; 20  } 21 
22 }
 1 class Book implements Cloneable {  2 
 3     private String title;  4     private int pageNum;  5     private Author author;  6 
 7     public Book clone() {  8         Book book = null;  9         try { 10             book = (Book) super.clone(); 11         } catch (CloneNotSupportedException e) { 12             // TODO Auto-generated catch block
13  e.printStackTrace(); 14  } 15         return book; 16  } 17 
18     public String getTitle() { 19         return title; 20  } 21 
22     public void setTitle(String title) { 23         this.title = title; 24  } 25 
26     public int getPageNum() { 27         return pageNum; 28  } 29 
30     public void setPageNum(int pageNum) { 31         this.pageNum = pageNum; 32  } 33 
34     public Author getAuthor() { 35         return author; 36  } 37 
38     public void setAuthor(Author author) { 39         this.author = author; 40  } 41 
42 }

2.測試:code

 1 package com.qqyumidi;  2 
 3 public class PrototypeTest {  4 
 5     public static void main(String[] args) {  6         Book book1 = new Book();  7         Author author = new Author();  8         author.setName("corn");  9         author.setAge(100); 10  book1.setAuthor(author); 11         book1.setTitle("好記性不如爛博客"); 12         book1.setPageNum(230); 13 
14         Book book2 = book1.clone(); 15         
16         System.out.println(book1 == book2);  // false
17         System.out.println(book1.getPageNum() == book2.getPageNum());   // true
18         System.out.println(book1.getTitle() == book2.getTitle());        // true
19         System.out.println(book1.getAuthor() == book2.getAuthor());        // true
20         
21  } 22 }

由輸出的結果能夠驗證說到的結論。由此咱們發現:雖然複製出來的對象從新在堆上開闢了內存空間,可是,對象中各屬性確保持相等。對於基本數據類型很好理解,但對於引用數據類型來講,則意味着此引用類型的屬性所指向的對象自己是相同的, 並無從新開闢內存空間存儲。換句話說,引用類型的屬性所指向的對象並無複製。

由此,咱們將其稱之爲淺複製。當複製後的對象的引用類型的屬性所指向的對象也從新得以複製,此時,稱之爲深複製。

 

 

2、深複製:

 Java中的深複製通常是經過對象的序列化和反序列化得以實現。序列化時,須要實現Serializable接口。

下面仍是以Book爲例,看下深複製的通常實現過程:

1.定義Book類和Author類(注意:不只Book類須要實現Serializable接口,Author一樣也須要實現Serializable接口!!):

 1 class Author implements Serializable{  2 
 3     private String name;  4     private int age;  5 
 6     public String getName() {  7         return name;  8  }  9 
10     public void setName(String name) { 11         this.name = name; 12  } 13 
14     public int getAge() { 15         return age; 16  } 17 
18     public void setAge(int age) { 19         this.age = age; 20  } 21 
22 }
 1 class Book implements Serializable {  2 
 3     private String title;  4     private int pageNum;  5     private Author author;  6 
 7     public Book deepClone() throws IOException, ClassNotFoundException{  8         // 寫入當前對象的二進制流 
 9         ByteArrayOutputStream bos = new ByteArrayOutputStream(); 10         ObjectOutputStream oos = new ObjectOutputStream(bos); 11         oos.writeObject(this); 12         
13         // 讀出二進制流產生的新對象 
14         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 15         ObjectInputStream ois = new ObjectInputStream(bis); 16         return (Book) ois.readObject(); 17  } 18     
19     public String getTitle() { 20         return title; 21  } 22 
23     public void setTitle(String title) { 24         this.title = title; 25  } 26 
27     public int getPageNum() { 28         return pageNum; 29  } 30 
31     public void setPageNum(int pageNum) { 32         this.pageNum = pageNum; 33  } 34 
35     public Author getAuthor() { 36         return author; 37  } 38 
39     public void setAuthor(Author author) { 40         this.author = author; 41  } 42 
43 }

2.測試:

 1 public class PrototypeTest {  2 
 3     public static void main(String[] args) throws ClassNotFoundException, IOException {  4         Book book1 = new Book();  5         Author author = new Author();  6         author.setName("corn");  7         author.setAge(100);  8  book1.setAuthor(author);  9         book1.setTitle("好記性不如爛博客"); 10         book1.setPageNum(230); 11 
12         Book book2 = book1.deepClone(); 13         
14         System.out.println(book1 == book2);  // false
15         System.out.println(book1.getPageNum() == book2.getPageNum());   // true
16         System.out.println(book1.getTitle() == book2.getTitle());        // false
17         System.out.println(book1.getAuthor() == book2.getAuthor());        // false
18         
19  } 20 }

從輸出結果中能夠看出,深複製不只在堆內存上開闢了空間以存儲複製出的對象,甚至連對象中的引用類型的屬性所指向的對象也得以複製,從新開闢了堆空間存儲。

 

至此:設計模式中的建立型模式總結完畢,一共有五種建立型模式,分別爲:單例模式(SingleTon)、建造者模式(Builder)、工廠方法模式(Factory Method)、抽象工廠模式(Abstract Factory)和原型模式(Prototype)。每種模式適用於不一樣的場景,具體應用時需注意區分。

相關文章
相關標籤/搜索