Prototype定義
利用雛型模式可以拷貝這些物件並建立新物件,主要可以分為淺拷貝與深拷貝 1. 淺拷貝: 有稱影子拷貝,拷貝原物件並將原有的物件所以欄位重新建立一次,只針對需要的欄位完整複製,其他部分則是參照的方式完成。
Prototype使用情況
- 當有需要複製原物件,還當作副本提供其他系統修改,來保護原物件
- 當產生new 物件需要浪費很多時間或是很多資訊時,可以考慮用原型模式完成 3.
Prototype案例 -淺拷貝
我們利用員工薪水的例子來說明原型,在一家公司假設工程師基本薪水有30K,假設每天都需要加班一小時,一個月上班22天要如何算出月薪。不同語言支援的複製功能有不同的規範,使用java需要讓員工物件有複製的功能需要實作 java.lang.Cloneable這個介面。
IEmploy.java : 為抽象員工物件、EngineerShallow.java實作員工物件、Profile.java:為員工基本資料,我們為了可以快速算出員工薪水利用淺拷貝來快速建立其他員工資料。但是淺拷貝有一個缺點就是當執行baseProfile.setName("Mary")時,emp1也會跟著改變,因為淺拷貝當拷貝物件時,有參照外部的物件,也跟著參照並不會完整複製。
package design.Prototype; /** * name: IEmploy.java * descirpt: 員工薪水抽象物件,主要用來建立基本資料、薪水、加班費等等 * Created by bryant on 2017/1/8. */ abstract class IEmploy { //基本薪水 abstract protected void setBaseSalary(BigDecimal baseSalary); //津貼 abstract protected void setBonus(BigDecimal bouns); //加班費 abstract protected void setOvertimeSalary(int hour); //基本資料 abstract protected void setProfile(Profile profile); //基本薪水 abstract protected BigDecimal getBaseSalary() ; //津貼 abstract protected BigDecimal getBonus() ; //加班費 abstract protected BigDecimal getOvertimeSalary() ; //全部薪水 abstract protected BigDecimal getFullSalary() ; //基本資料 abstract protected Profile getProfile(); }
package design.Prototype; /** * name: Profile.java * descirpt:ion: 個人基本資料: 姓名 * Created by bryant on 2017/1/8. */ public class Profile implements Cloneable { private String name ; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
package design.Prototype; import java.math.BigDecimal; import java.math.RoundingMode; /** * name: EngineerShallow.java * descirpt: 淺複製員工資料 * Created by bryant on 2017/1/8. */ public class EngineerShallow extends IEmploy implements Cloneable{ private Profile profile ; private BigDecimal baseSalary; private BigDecimal bouns; private BigDecimal overtimeSalary; @Override protected void setProfile(Profile profile){ this.profile = profile; } @Override public Profile getProfile() { return profile; } @Override protected void setBaseSalary(BigDecimal baseSalary) { this.baseSalary = baseSalary ; } @Override protected void setBonus(BigDecimal bouns) { this.bouns = bouns ; } @Override protected void setOvertimeSalary(int hour) { this.overtimeSalary = (this.baseSalary.divide(new BigDecimal((240)), RoundingMode.HALF_EVEN)). multiply(new BigDecimal("1.33")). multiply(new BigDecimal(hour)); } @Override protected BigDecimal getBaseSalary() { return this.baseSalary; } @Override protected BigDecimal getBonus() { return this.bouns; } @Override protected BigDecimal getOvertimeSalary() { return this.overtimeSalary; } @Override protected BigDecimal getFullSalary() { return this.baseSalary.add(this.overtimeSalary).add(this.bouns); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { String s = "name:"+this.profile.getName()+"," + "base Salary: "+this.getBaseSalary()+"," + "bonus Salary: "+this.getBonus()+"," + "overtime Salary: "+this.getOvertimeSalary()+","+ "full Salary: "+this.getFullSalary()+"," ; return s; } //測試Prototype public static void main(String argsp[]){ EngineerShallow baseEngineer = new EngineerShallow() ; Profile baseProfile = new Profile(); baseProfile.setName("baseProfile"); baseEngineer.setProfile(baseProfile); baseEngineer.setBaseSalary(new BigDecimal(30000)); baseEngineer.setBonus(new BigDecimal(1000)); baseEngineer.setOvertimeSalary(40); System.out.println(baseEngineer.toString()); try { EngineerShallow emp1 = (EngineerShallow) baseEngineer.clone() ; emp1.setBaseSalary(new BigDecimal(35000)); System.out.println(emp1.toString()); baseProfile.setName("Mary"); System.out.println(emp1.toString()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
Prototype案例 -深拷貝
為了解決淺參照的問題,我們利用深拷貝可以達到外部參照也會複製完整的一份物件。由下面程式看到clone函式Profile物件會自我複製,就不會因為EngineerDeep有參照外部的物件而造成問題。
package design.Prototype; import java.math.BigDecimal; import java.math.RoundingMode; /** * name: EngineerDeep.java * descirpt: 深拷貝連外部參照也會拷貝一份 * Created by bryant on 2017/1/8. */ public class EngineerDeep extends IEmploy implements Cloneable{ private Profile profile ; private BigDecimal baseSalary; private BigDecimal bouns; private BigDecimal overtimeSalary; @Override protected void setProfile(Profile profile){ this.profile = profile; } @Override public Profile getProfile() { return profile; } @Override protected void setBaseSalary(BigDecimal baseSalary) { this.baseSalary = baseSalary ; } @Override protected void setBonus(BigDecimal bouns) { this.bouns = bouns ; } @Override protected void setOvertimeSalary(int hour) { this.overtimeSalary = (this.baseSalary.divide(new BigDecimal((240)), RoundingMode.HALF_EVEN)). multiply(new BigDecimal("1.33")). multiply(new BigDecimal(hour)); } @Override protected BigDecimal getBaseSalary() { return this.baseSalary; } @Override protected BigDecimal getBonus() { return this.bouns; } @Override protected BigDecimal getOvertimeSalary() { return this.overtimeSalary; } @Override protected BigDecimal getFullSalary() { return this.baseSalary.add(this.overtimeSalary).add(this.bouns); } @Override protected Object clone() throws CloneNotSupportedException { EngineerDeep engineerDeep = (EngineerDeep) super.clone() ; Profile profile = (Profile) engineerDeep.getProfile().clone(); engineerDeep.setProfile(profile); return engineerDeep; } @Override public String toString() { String s = "name:"+this.profile.getName()+"," + "profile :"+this.profile.toString()+","+ "base Salary: "+this.getBaseSalary()+"," + "bonus Salary: "+this.getBonus()+"," + "overtime Salary: "+this.getOvertimeSalary()+","+ "full Salary: "+this.getFullSalary()+"," ; return s; } //測試Prototype public static void main(String argsp[]){ EngineerDeep baseEngineer = new EngineerDeep() ; Profile baseProfile = new Profile(); baseProfile.setName("baseProfile"); baseEngineer.setProfile(baseProfile); baseEngineer.setBaseSalary(new BigDecimal(30000)); baseEngineer.setBonus(new BigDecimal(1000)); baseEngineer.setOvertimeSalary(40); System.out.println(baseEngineer.toString()); try { EngineerDeep emp1 = (EngineerDeep) baseEngineer.clone() ; emp1.setBaseSalary(new BigDecimal(35000)); System.out.println(emp1.toString()); baseProfile.setName("Mary"); System.out.println(emp1.toString()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
Prototype and Factory 差異
待續...
留言
張貼留言