【设计模式】原型模式 ( 浅拷贝 | 深拷贝 | 原型与单例冲突 | 禁用 final )
文章目錄
- I . 原型模式 總結(jié)
- II . 原型模式 淺拷貝
- III . 原型模式 深拷貝
- IV . 原型模式 與 單例
- V . 原型模式 中的 final 關(guān)鍵字 ( 禁止出現(xiàn) )
I . 原型模式 總結(jié)
1 . 原型模式本質(zhì)及性能 : 原型模式使用 clone 方法克隆對象 , 其本質(zhì)是在內(nèi)存中拷貝二進(jìn)制數(shù)據(jù) , 這種方式要比調(diào)用 new 構(gòu)造函數(shù)性能高得多 ;
2 . clone 核心是內(nèi)存拷貝 : clone 對象不使用復(fù)用原有對象 , 是在內(nèi)存中的另一個地址空間復(fù)制了一份一模一樣的數(shù)據(jù) , 然后將其首地址給新對象的引用 ;
3 . 原型模式適用場景 : ① 節(jié)省資源 ( 內(nèi)存 CPU 硬件等 ) , ② 構(gòu)造函數(shù)復(fù)雜 ( 計算繁瑣 耗時 ) , ③ 創(chuàng)建大量對象 ;
4 . 原型模式實(shí)現(xiàn) : 原型模式類實(shí)現(xiàn) Cloneable 接口 , 實(shí)現(xiàn)其中的 clone 方法 ;
① 淺拷貝實(shí)現(xiàn) : 淺拷貝默認(rèn)調(diào)用 super.clone ;
② 深拷貝實(shí)現(xiàn) : 深拷貝需要調(diào)用 每個引用成員對象的 clone 方法創(chuàng)建成員對象 , 然后賦值給新的原型模式創(chuàng)建的對象 , 作為其中的成員 ;
5 . 注意拷貝方式 : 默認(rèn)淺拷貝 , 如果類中有引用類型成員變量 , 需要考慮深拷貝問題 , 可能會出現(xiàn)多個對象持有同一個引用變量 ;
II . 原型模式 淺拷貝
1 . 淺拷貝 : 調(diào)用 clone 對象拷貝內(nèi)存中的數(shù)據(jù)時 , 要注意拷貝的是基礎(chǔ)數(shù)據(jù)類型 , 對于數(shù)組 , 集合 , 自定義類等引用數(shù)據(jù)類型僅拷貝地址 , 會造成所有的對象都持有同一個內(nèi)存地址的引用成員 ;
① 基礎(chǔ)數(shù)據(jù)類型 : 如果類中全部是基礎(chǔ)數(shù)據(jù)類型 , 使用 clone 可以將該類完整的復(fù)制一份 ;
② 引用數(shù)據(jù)類型 : 如果類中有引用類型成員 , 只是拷貝該成員的地址 , 所有的拷貝創(chuàng)建的原型模式實(shí)例對象都持有同一個引用 , 如果修改該引用成員的值 , 所有的原型對象實(shí)例的值都會跟著修改 ;
2 . 淺拷貝示例 :
① 原型模式類 Student : 該類中持有 Vector<String> courses 引用數(shù)據(jù)類型 , 調(diào)用 clone 方法在內(nèi)存中復(fù)制對象時 , 僅復(fù)制了對象的地址 , 即將該引用的地址賦值給了 clone 出的對象 ;
package kim.hsl.design.prototype.shallowcopy;import java.util.Vector;/*** 淺拷貝示例*/ public class Student implements Cloneable {private String name;private int age;//該類在拷貝時 , 如果使用淺拷貝 , 只是將地址拷貝走了 , 兩個對象實(shí)際上用的是同一個對象private Vector<String> courses = new Vector<>();public Student() {System.out.println("調(diào)用 Student 默認(rèn)構(gòu)造函數(shù)");}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Vector<String> getCourses() {return courses;}public void setCourses(Vector<String> courses) {this.courses = courses;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", courses=" + courses +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {System.out.println("調(diào)用 Student clone 方法");return super.clone();} }② 測試類 Main : 此處創(chuàng)建了兩個 Student 實(shí)例對象 , 但是兩個對象都持有同一個 Vector<String> courses 引用數(shù)據(jù)類型成員 , 當(dāng)修改其中一個成員時 , 兩個對象中的該成員都會改變 ;
package kim.hsl.design.prototype.shallowcopy;public class Main {public static void main(String[] args) {try {//測試使用 clone 方法實(shí)現(xiàn)的原型模式 , 使用原型模式創(chuàng)建 2 個對象Student newStudent = new Student();// 1 . 使用 clone 方法創(chuàng)建對象1Student student = (Student) newStudent.clone();student.setName("Tom");student.setAge(10);student.getCourses().add("數(shù)學(xué)");// 2 . 使用 clone 方法創(chuàng)建對象2Student student2 = (Student) newStudent.clone();student2.setName("Jerry");student2.setAge(18);student2.getCourses().add("語文");System.out.println("student : " + student + "\nstudent2 : " + student2);} catch (CloneNotSupportedException e) {//捕獲 clone 方法可能產(chǎn)生的異常e.printStackTrace();}} }③ 執(zhí)行結(jié)果 : 調(diào)用第一個對象 add 方法 , 在 vector 集合中添加了 “數(shù)學(xué)” 字符串 , 調(diào)用第二個對象的 add 方法 , 向 courses 集合中添加 “語文” 字符串 , 理論上兩個分別是 “數(shù)學(xué)” 和 “語文” , 但是此處卻都變成了 “數(shù)學(xué)” “語文” 兩個課程 , 說明兩個原型模式對象持有的 Vector<String> courses 變量是指向同一個內(nèi)存地址的 ;
調(diào)用 Student 默認(rèn)構(gòu)造函數(shù) 調(diào)用 Student clone 方法 調(diào)用 Student clone 方法 student : Student{name='Tom', age=10, courses=[數(shù)學(xué), 語文]} student2 : Student{name='Jerry', age=18, courses=[數(shù)學(xué), 語文]}III . 原型模式 深拷貝
1 . 深拷貝策略 : 深拷貝時需要在 clone 方法中 , 調(diào)用引用數(shù)據(jù)類型本身的 clone 對象 , 在將其賦值給被拷貝的原型模式實(shí)例對象 ;
2 . 深拷貝 clone 方法流程 :
① 創(chuàng)建實(shí)例對象 : 通過 clone 方法 , 創(chuàng)建原型模式類的實(shí)例對象 , 此時該對象的引用成員處于淺拷貝狀態(tài) ;
② 拷貝引用成員 : 調(diào)用原型模式類對象成員的 clone 對象 , 創(chuàng)建新的成員對象 , 將新的成員對象賦值給克隆出的原型模式對象 ;
③ 返回新的對象 : 返回 clone 創(chuàng)建的原型模式實(shí)例對象 ;
3 . 示例代碼 :
① 原型模式深拷貝示例 : 深拷貝與淺拷貝只是在 clone 方法中表現(xiàn)不同 , 其它代碼一致 ; 在 clone 方法中需要針對引用類型進(jìn)行克隆 ;
package kim.hsl.design.prototype.deepcopy;import java.util.Vector;/*** 淺拷貝示例*/ public class Student implements Cloneable {private String name;private int age;//該類在拷貝時 , 如果使用淺拷貝 , 只是將地址拷貝走了 , 兩個對象實(shí)際上用的是同一個對象private Vector<String> courses = new Vector<>();public Student() {System.out.println("調(diào)用 Student 默認(rèn)構(gòu)造函數(shù)");}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Vector<String> getCourses() {return courses;}public void setCourses(Vector<String> course) {this.courses = course;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", course=" + courses +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {System.out.println("調(diào)用 Student clone 方法");//1 . 首先拷貝一個基本對象Student student = (Student) super.clone();//2 . 將引用類型的對象單獨(dú)克隆賦值student.courses = (Vector<String>) this.courses.clone();//3 . 返回創(chuàng)建的新的對象return student;} }② 測試代碼 :
package kim.hsl.design.prototype.deepcopy;public class Main {public static void main(String[] args) {try {//測試使用 clone 方法實(shí)現(xiàn)的原型模式 , 使用原型模式創(chuàng)建 2 個對象Student newStudent = new Student();// 1 . 使用 clone 方法創(chuàng)建對象1Student student = (Student) newStudent.clone();student.setName("Tom");student.setAge(10);student.getCourses().add("數(shù)學(xué)");// 2 . 使用 clone 方法創(chuàng)建對象2Student student2 = (Student) newStudent.clone();student2.setName("Jerry");student2.setAge(18);student2.getCourses().add("語文");System.out.println("student : " + student + "\nstudent2 : " + student2);} catch (CloneNotSupportedException e) {//捕獲 clone 方法可能產(chǎn)生的異常e.printStackTrace();}} }③ 運(yùn)行結(jié)果 : 原型模式的兩個實(shí)例對象的互不干擾 ;
調(diào)用 Student 默認(rèn)構(gòu)造函數(shù) 調(diào)用 Student clone 方法 調(diào)用 Student clone 方法 student : Student{name='Tom', age=10, course=[數(shù)學(xué)]} student2 : Student{name='Jerry', age=18, course=[語文]}
IV . 原型模式 與 單例
1 . 原型模式 與 單例模式 :
① 原型模式 : 原型模式的核心是不調(diào)用構(gòu)造函數(shù) , 使用 clone 方法在內(nèi)存中克隆對象 ;
② 單例模式 : 單例模式的核心是私有化構(gòu)造函數(shù) , 控制外部用戶 , 不能隨意調(diào)用構(gòu)造函數(shù)創(chuàng)建對象 ;
2 . Cloneable 破壞了單例模式 : 此處二者就出現(xiàn)了矛盾 , 如果單例類 , 實(shí)現(xiàn)了 Cloneable 接口 , 那么該類就可以調(diào)用 clone 方法創(chuàng)建另外的實(shí)例對象 , 因此破壞了單例模式 ;
3 . 解決方案 :
① 不實(shí)現(xiàn) Cloneable 接口 : 單例模式中不要實(shí)現(xiàn) Cloneable 接口 , 不提供內(nèi)存拷貝功能 ;
② clone 中調(diào)用單例 : 如果必須實(shí)現(xiàn) Cloneable 接口 , 那么在重寫的 clone 方法中 , 調(diào)用獲取單例類的方法 , 不要進(jìn)行內(nèi)存對象拷貝創(chuàng)建新的實(shí)例對象 ;
V . 原型模式 中的 final 關(guān)鍵字 ( 禁止出現(xiàn) )
1 . final 作用 : final 用于修飾常量 , 被 final 修飾的變量無法重新賦值 ;
2 . Cloneable 實(shí)現(xiàn)類成員不要使用 final : 在原型模式的類中 , 實(shí)現(xiàn)了 Cloneable 接口 , 重寫了 clone 方法 , 其類對象的成員不能被 final 修飾 , 否則無法重新賦值 ;
總結(jié)
以上是生活随笔為你收集整理的【设计模式】原型模式 ( 浅拷贝 | 深拷贝 | 原型与单例冲突 | 禁用 final )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【设计模式】原型模式 ( 概念简介 |
- 下一篇: 【设计模式】外观模式 ( 概念 | 适用