原型模式(Prototype )

簡單的複製粘貼代碼會對之後的程序維護形成巨大的工做量。java

爲了不這種災難的誕生,咱們今天來學習原型模式,仍是用代碼來逐步過渡到原型模式(建立型模式)的講解吧。spring

 

假設今天開學啦,有小明,小紅,小豬入學報到!數據庫

先來一個學生檔案類,有院系,入學時間,畢業時間幾個屬性,和屬性的set/get方法設計模式

 1 public class StudentFiles {  2     private String department;  3     private String admissionTime;  4     private String graduationTime;  5 
 6     public StudentFiles(String department, String admissionTime, String graduationTime) {  7         this.department = department;  8         this.admissionTime = admissionTime;  9         this.graduationTime = graduationTime; 10  } 11 
12  @Override 13     public String toString() { 14         return "StudentFiles{" +
15                 "department='" + department + '\'' +
16                 ", admissionTime='" + admissionTime + '\'' +
17                 ", graduationTime='" + graduationTime + '\'' +
18                 '}'; 19  } 20 }

再來一個學生類,有姓名,年齡和檔案三個屬性ide

 1 public class Student {  2     private String name;  3     private int age;  4     private StudentFiles studentFiles;  5 
 6     public Student(String name, int age) {  7         this.name = name;  8         this.age = age;  9  } 10 
11     public StudentFiles getStudentFiles() { 12         return studentFiles; 13  } 14 
15     public void setStudentFiles(StudentFiles studentFiles) { 16         this.studentFiles = studentFiles; 17  } 18 
19  @Override 20     public String toString() { 21         return "Student{" +
22                 "name='" + name + '\'' +
23                 ", age=" + age +
24                 ", studentFiles=" + studentFiles +
25                 '}'; 26  } 27 } 28 
29 
30 如今開始給他們辦理入學手續 31 客戶端代碼 32 public class Client { 33     public static void main(String[] args) { 34         StudentFiles xiaohongFiles = new StudentFiles("計算機系","2019-5-8","2023-5-8"); 35         Student xiaohong=new Student("小紅",22); 36  xiaohong.setStudentFiles(xiaohongFiles); 37 
38         StudentFiles xiaomingFiles = new StudentFiles("計算機系","2019-5-8","2023-5-8"); 39         Student xiaoming=new Student("小明",21); 40  xiaoming.setStudentFiles(xiaomingFiles); 41 
42         StudentFiles xiaozhuFiles = new StudentFiles("計算機系","2019-5-8","2023-5-8"); 43         Student xiaozhu=new Student("小豬",23); 44  xiaozhu.setStudentFiles(xiaozhuFiles); 45 
46  System.out.println(xiaohong.toString()); 47  System.out.println(xiaoming.toString()); 48  System.out.println(xiaozhu.toString()); 49  } 50 }

結果學習

如今三位同窗開開心心的去上學了,可是咱們發現檔案是個屬性相同的對象。咱們在建立的時候只是簡單的複製粘貼過來的,複製粘貼的代碼越多維護代碼也就越多 。this

 

那咱們只製做一份檔案試試?spa

 1 public class Client {  2     public static void main(String[] args) {  3         StudentFiles studentFiles = new StudentFiles("計算機系","2019-5-8","2023-5-8");  4 
 5         Student xiaohong=new Student("小紅",22);  6  xiaohong.setStudentFiles(studentFiles);  7 
 8         Student xiaoming=new Student("小明",21);  9  xiaoming.setStudentFiles(studentFiles); 10 
11         Student xiaozhu=new Student("小豬",23); 12  xiaozhu.setStudentFiles(studentFiles); 13 
14  System.out.println(xiaohong.toString()); 15  System.out.println(xiaoming.toString()); 16  System.out.println(xiaozhu.toString()); 17  } 18 }

結果設計

看了下結果是對的,但是別開心的太早。
如今小豬同窗表現一點都很差,不能再學校按時畢業了,要延期一年。code

1 studentFiles.setGraduationTime("2024-5-8");

結果

好了,如今小明和小紅都要延期畢業了,是否是會氣死其餘兩個同窗。

分析一下緣由:咱們只建立了一份檔案,讓三個同窗的檔案都指向了這個檔案了,三個檔案是同一份檔案,這固然不合乎常理了。每一個人的檔案都應該屬於本身,而不是和別人共用。

究其發生上面狀況的緣由是由於咱們既不想複製代碼,偷懶又出現了大問題。那麼存在那種咱們經過代碼來複制對象的可能的方法嗎?
有的就是接下來出場的原型模式:

 

由於這個模式使用頻繁,全部java已經給咱們封裝好了,咱們只須要掌握使用便可。

首先讓類實現Cloneable接口,接着重寫clone方法

1 public Object clone() throws CloneNotSupportedException{ 2     return super.clone(); 3 }

此時的客戶端代碼

1 StudentFiles xiaohongStudentFiles= (StudentFiles) studentFiles.clone(); 2 StudentFiles xiaomingStudentFiles= (StudentFiles) studentFiles.clone(); 3 StudentFiles xiaozhuStudentFiles= (StudentFiles) studentFiles.clone();

那咱們再來看看這樣複製真的能夠嗎,假設小豬不想和小紅作同窗了,他要轉到電信院去。

1 xiaozhuStudentFiles.setDepartment("電信院");

結果

既然咱們已經作好了偷懶的準備,爲何不進行到底呢?

其實咱們已經瞭解到來上學的同窗大多都是22歲,只有極個別是其餘年齡。

那咱們複製學生類好了,再給每一個學生都賦上他們的姓名便可。

1 public Object clone() throws CloneNotSupportedException{ 2     return super.clone(); 3 }

客戶端的代碼

public class Client { public static void main(String[] args) throws CloneNotSupportedException { StudentFiles studentFiles = new StudentFiles("計算機系","2019-5-8","2023-5-8"); Student student=new Student(22);//student的原型
 student.setStudentFiles(studentFiles); Student xiaohong= (Student) student.clone(); xiaohong.setName("小紅"); Student xiaoming=(Student) student.clone(); xiaoming.setName("小明"); xiaoming.setAge(15); Student xiaozhu=(Student) student.clone(); xiaozhu.setName("小豬"); System.out.println(xiaohong.toString()); System.out.println(xiaoming.toString()); System.out.println(xiaozhu.toString()); } } 

咱們發現小明原來是個神通,才15歲是同窗中的特例,咱們爲他修改下年齡。

結果

聰明的小明提早一年修滿了全部學分,他要提早畢業了。

1 StudentFiles tmp = xiaoming.getStudentFiles(); 2 tmp.setGraduationTime("2022-5-8"); 3 xiaoming.setStudentFiles(tmp);

結果

能夠看到同窗們都沾了小明的光提早畢業了,可是學校不容許這樣的狀況發生呀,咱們來研究下緣由吧:

咱們先了解淺拷貝和深拷貝的概念

淺拷貝:只拷貝基本數據類型,對於對象屬性拷貝其中的引用地址

深拷貝:複製的時候基本數據類型和對象引用都拷貝一份

 

很顯然咱們的拷貝是屬於淺拷貝,咱們修改年齡對其餘人沒有影響,可是咱們修改學籍對象的時候,每一個拷貝的對象都發生了修改。
那java的深拷貝是怎麼實現的呢?

咱們修改一下Student的clon方法便可

1 public Object clone() throws CloneNotSupportedException{ 2     Student student=(Student)super.clone(); 3  student.setStudentFiles((StudentFiles)studentFiles.clone()); 4     return student; 5 }

結果

 

總結:
淺拷貝:複製基本數據類型,引用類型沒有進行復制  

步驟:

1.實現Cloneable接口

2.實現clone方法

1 public Object clone() throws CloneNotSupportedException{ 2         return super.clone(); 3     }

 


深拷貝:複製基本數據類型和引用類型

步驟:

1.實現Cloneable接口

2.實現clone方法

1 public Object clone() throws CloneNotSupportedException{ 2         Student student=(Student)super.clone(); 3  student.setStudentFiles((StudentFiles)studentFiles.clone()); 4         return student; 5     }

 


原型模式優勢:
1.抽象出共同點,僅須要修改對象間的不一樣點
2.大大減小JVM建立對象的時間

 

 

實際上是有遇到過相似的狀況的,只不過由於並無學習到這裏,當時使用了最笨的辦法一次次的new一個對象。

好比如今有一個student的list集合建立,而後批量插入數據庫。在循環處的new對象徹底能夠改爲(Student) student.clone(),修改其中的屬性便可。大大減小java徐理解建立對象的時間,同時代碼也相對簡潔。

 

到這裏建立型模式(建造者模式,工廠模式,原型模式)都搞定了,還剩下單例模式還沒寫博客了。

單例模式十分重要,運用spring的bean的建立上,是spring IOC的重要設計模式。

相關文章
相關標籤/搜索