《大話設計模式》閱讀筆記和總結。原書是C#編寫的,本人用Java實作了一遍,包括每種設計模式的UML圖實作和示例代碼實作。
目錄:
設計模式 Github位址: DesignPattern
說明
定義:原型模式(Prototype),用原型執行個體指定建立對象的種類,并且通過拷貝這些原型建立新的對象。
UML圖:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuAjNhBTMxUGZ4UGN1YWZ3MmNmRjYwEjZkJ2N0UzY1UTYfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
原型模式UML圖.png
代碼實作:
原型類
我們這裡使用java api中Cloneable接口
具體原型類
class ConcretePrototype1 implements Cloneable{
private String id;
public ConcretePrototype1(String id){
this.id = id;
}
public String getId(){
return id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
用戶端代碼
public class PrototypePattern {
public static void main(String[] args) throws CloneNotSupportedException {
ConcretePrototype1 p1 = new ConcretePrototype1("I");
ConcretePrototype1 c1 = (ConcretePrototype1) p1.clone();
System.out.println("Cloned():"+c1.getId());
}
}
運作結果
Cloned():I
示例
例子:用程式模拟寫履歷,要求有一個履歷類,必要有姓名,可以設定性别和年齡,可以設定工作經曆,最終需要三份履歷。
原型模式示例UML圖.png
工作經曆類
public class WorkExperence implements Serializable {
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
履歷類
public class Resume implements Cloneable,Serializable{
private String name;
private String sex;
private int age;
private WorkExperence workExperence;
public Resume(){
workExperence = new WorkExperence();
}
public void display() {
System.out.println(this.getName() + " " + this.getSex() + " "
+ this.getAge() + "\n工作經曆: "
+ this.getWorkExperence().getWorkDate() + " "
+ this.getWorkExperence().getCompany());
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public WorkExperence getWorkExperence() {
return workExperence;
}
public void setWorkExperence(String workDate,String company) {
workExperence.setCompany(company);
workExperence.setWorkDate(workDate);
}
}
用戶端調用
public class Main {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
copy();
}
public static void copy() throws CloneNotSupportedException {
Resume resumeA = new Resume();
resumeA.setName("大鳥");
resumeA.setAge(25);
resumeA.setSex("男");
resumeA.setWorkExperence("2015-2016","A公司");
Resume resumeB = (Resume) resumeA.clone();
resumeB.setWorkExperence("2016-2017","B公司");
Resume resumeC = (Resume) resumeA.clone();
resumeC.setWorkExperence("2017-2018","C公司");
resumeA.display();
resumeB.display();
resumeC.display();
}
}
大鳥 男 25
工作經曆: 2017-2018 C公司
大鳥 男 25
工作經曆: 2017-2018 C公司
大鳥 男 25
工作經曆: 2017-2018 C公司
我們發現,設定的工作經曆并沒有正确的顯示。原因是:如果複制的字段是值類型的,則對該字段執行逐位複制,如果字段是引用類型,則複制引用但不複制引用的對象,是以原始對象及其複本引用同一對象。
深拷貝實作
原型模式示例深拷貝UML圖.png
履歷類增加deepClone()方法
public class Resume implements Cloneable,Serializable{
// ……
public Object deepClone() throws IOException, ClassNotFoundException {
// 将對象寫入流内
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 從流内讀出對象
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
return ois.readObject();
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
copy();
System.out.println("==============");
deepCopy();
}
public static void copy() throws CloneNotSupportedException {
Resume resumeA = new Resume();
resumeA.setName("大鳥");
resumeA.setAge(25);
resumeA.setSex("男");
resumeA.setWorkExperence("2015-2016","A公司");
Resume resumeB = (Resume) resumeA.clone();
resumeB.setWorkExperence("2016-2017","B公司");
Resume resumeC = (Resume) resumeA.clone();
resumeC.setWorkExperence("2017-2018","C公司");
resumeA.display();
resumeB.display();
resumeC.display();
}
public static void deepCopy() throws IOException, ClassNotFoundException {
Resume resumeA = new Resume();
resumeA.setName("大鳥");
resumeA.setAge(25);
resumeA.setSex("男");
resumeA.setWorkExperence("2015-2016","A公司");
Resume resumeB = (Resume) resumeA.deepClone();
resumeB.setWorkExperence("2016-2017","B公司");
Resume resumeC = (Resume) resumeA.deepClone();
resumeC.setWorkExperence("2017-2018","C公司");
resumeA.display();
resumeB.display();
resumeC.display();
}
}
運作結果:
大鳥 男 25
工作經曆: 2017-2018 C公司
大鳥 男 25
工作經曆: 2017-2018 C公司
大鳥 男 25
工作經曆: 2017-2018 C公司
==============
大鳥 男 25
工作經曆: 2015-2016 A公司
大鳥 男 25
工作經曆: 2016-2017 B公司
大鳥 男 25
工作經曆: 2017-2018 C公司