首先對原型模式進行一個簡單概念說明:經過一個已經存在的對象,複製出更多的具備與此對象具備相同類型的新的對象。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)。每種模式適用於不一樣的場景,具體應用時需注意區分。