簡單的複製粘貼代碼會對之後的程序維護形成巨大的工做量。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的重要設計模式。