四、原型模式與建造者模式詳解

5.原型模式

5.1.課程目標

1、掌握原型模式和建造者模式的應用場景

2、掌握原型模式的淺克隆和深克隆的寫法。

3、掌握建造者模式的基本寫法。

4、瞭解克隆是如何破壞單例的。

5、瞭解原型模式的優、缺點

6、掌握建造者模式和工廠模式的區別。

5.2.內容定位

1、已瞭解並掌握工廠模式的人群。

2、已瞭解並掌握單例模式。

3、聽說過原型模式,但不知道應用場景的人群。

5.3.定義

原型模式(PrototypePattern)是指原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象,屬於創建型模式。

官方原文:Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.

原型模式的核心在於拷貝原型對象。以系統中已存在的一個對象為原型,直接基於內存二進制流進行拷貝,無需再經歷耗時的對象初始化過程(不調用構造函數),性能提升許多。當對象的構建過程比較耗時時,可以利用當前系統中已存在的對象作為原型,對其進行克隆(一般是基於二進制流的複製),躲避初始化過程,使得新對象的創建時間大大減少。下面,我們來看看原型模式類結構圖:

四、原型模式與建造者模式詳解

從 UML 圖中,我們可以看到,原型模式 主要包含三個角色:

客戶(Client):客戶類提出創建對象的請求。

抽象原型(Prototype):規定拷貝接口。

具體原型(Concrete Prototype):被拷貝的對象。

注:對不通過 new 關鍵字,而是通過對象拷貝來實現創建對象的模式就稱作原型模式。

5.4.原型模式的應用場景

你一定遇到過大篇幅getter、setter賦值的場景。

代碼非常工整,命名非常規範,註釋也寫的很全面,其實這就是原型模式的需求場景。但是,大家覺 得這樣的代碼優雅嗎?我認為,這樣的代碼屬於純體力勞動。那原型模式,能幫助我們解決這樣的問題。

原型模式主要適用於以下場景:

1、類初始化消耗資源較多。

2、new產生的一個對象需要非常繁瑣的過程(數據準備、訪問權限等)

3、構造函數比較複雜。

4、循環體中生產大量對象時。

在 Spring 中,原型模式應用得非常廣泛。例如 scope=“prototype”,在我們經常用的 JSON.parseObject()也是一種原型模式。

5.5.原型模式的通用寫法(淺拷貝)

一個標準的原型模式代碼,應該是這樣設計的。先創建原型IPrototype接口:

<code> public interface IPrototype {
     T clone();
 }
/<code>

創建具體需要克隆的對象ConcretePrototype

<code> public class ConcretePrototype implements IPrototype {
 ​
     private int age;
     private String name;
 ​
     public int getAge() {
         return age;
    }
 ​
     public void setAge(int age) {
         this.age = age;
    }
 ​
     public String getName() {
         return name;
    }

 ​
     public void setName(String name) {
         this.name = name;
    }
 ​
     @Override
     public ConcretePrototype clone() {
         ConcretePrototype concretePrototype = new ConcretePrototype();
         concretePrototype.setAge(this.age);
         concretePrototype.setName(this.name);
         return concretePrototype;
    }
 ​
     @Override
     public String toString() {
         return "ConcretePrototype{" +
                 "age=" + age +
                 ", name='" + name + '\\'' +
                 '}';
    }
 }/<code>

測試代碼:

<code> public class Client {
     public static void main(String[] args) {
         //創建原型對象
         ConcretePrototype prototype = new ConcretePrototype();
         prototype.setAge(18);
         prototype.setName("Tom");
         System.out.println(prototype);
 ​
         //拷貝原型對象
         ConcretePrototype cloneType = prototype.clone();
         System.out.println(cloneType);
    }
 }/<code>

運行結果:

<code> ConcretePrototype{age=18, name='Tom'}
 ConcretePrototype{age=18, name='Tom'}/<code>

這時候,有小夥伴就問了,原型模式就這麼簡單嗎?對,就是這麼簡單。在這個簡單的場景之下,看上 去操作好像變複雜了。但如果有幾百個屬性需要複製,那我們就可以一勞永逸。但是,上面的複製過程 是我們自己完成的,在實際編碼中,我們一般不會浪費這樣的體力勞動,JDK已經幫我們實現了一個現 成的API,我們只需要實現Cloneable接口即可。來改造一下代碼,修改ConcretePrototype類:

<code> @Data
 public class ConcretePrototype implements Cloneable {
 ​
     private int age;
     private String name;
 ​
     @Override
     public ConcretePrototype clone() {
         try {
             return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
             e.printStackTrace();
             return null;
        }
    }
 }/<code>

重新運行,也會得到同樣的結果。

有了JDK的支持再多的屬性複製我們也能輕而易舉地搞定了。下面我 們再來做一個測試,給ConcretePrototype增加一個個人愛好的屬性hobbies:

<code> @Data
 public class ConcretePrototype implements Cloneable {
 ​
     private int age;
     private String name;
     private List<string> hobbies;
 ​
     @Override
     public ConcretePrototype clone() {
         try {
             return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
             e.printStackTrace();
             return null;
        }
    }
 }/<string>/<code>

修改客戶端測試代碼:

<code> public class Client { 

 ​
     public static void main(String[] args) {
         //創建原型對象
         ConcretePrototype prototype = new ConcretePrototype();
         prototype.setAge(18);
         prototype.setName("Tom");
         List<string> hobbies = new ArrayList<string>();
         hobbies.add("書法");
         hobbies.add("美術");
         prototype.setHobbies(hobbies);
 ​
         //拷貝原型對象
         ConcretePrototype cloneType = prototype.clone();
         cloneType.getHobbies().add("技術控");
         System.out.println("原型對象:" + prototype);
         System.out.println("克隆對象:" + cloneType);
         System.out.println(prototype == cloneType);
         
         System.out.println("原型對象的愛好:" + prototype.getHobbies());
         System.out.println("克隆對象的愛好:" + cloneType.getHobbies());
         System.out.println(prototype.getHobbies() == cloneType.getHobbies());
    }
 }/<string>/<string>/<code>

運行結果:

<code> 原型對象:ConcretePrototype(age=18, name=Tom, hobbies=[書法, 美術, 技術控])
 克隆對象:ConcretePrototype(age=18, name=Tom, hobbies=[書法, 美術, 技術控])
 false
 原型對象的愛好:[書法, 美術, 技術控]
 克隆對象的愛好:[書法, 美術, 技術控]
 true/<code>

我們給,複製後的克隆對象新增一項愛好,發現原型對象也發生了變化,這顯然不符合我們的預期。 因為我們希望克隆出來的對象應該和原型對象是兩個獨立的對象,不應該再有聯繫了。從測試結果分析 來看,應該是hobbies共用了一個內存地址,意味著複製的不是值,而是引用的地址。這樣的話,如果我們修改任意一個對象中的屬性值,prototype 和cloneType的hobbies值都會改變。這就是我們常 說的淺克隆。只是完整複製了值類型數據,沒有賦值引用對象。換言之,所有的引用對象仍然指向原來 的對象,顯然不是我們想要的結果。那如何解決這個問題呢?下面我們來看深度克隆繼續改造。

擴展知識:String對象在內存中是不可變的(final類型),雖然克隆後,兩個對象String的引用指向的是同一個內存地址,但是如果給克隆後的對象的String屬性改變值,那麼相當於是在內存中重新開闢了一塊內存來存儲這個改變的值,而此時的String屬性對象就指向了該內存值,所以這個時候克隆前和克隆後對象的String屬性是不一樣的)。

String 每次賦值,相當於new String()。

5.6.使用序列化實現深度克隆

在上面的基礎上我們繼續改造,來看代碼,增加一個deepClone()方法:

<code> @Data
 public class ConcretePrototype implements Cloneable,Serializable {
 ​
     private int age;
     private String name;
     private List<string> hobbies;
 ​
     @Override
     public ConcretePrototype clone() {
         try {
             return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
             e.printStackTrace();
             return null;
        }
    }
 ​
     public ConcretePrototype deepClone(){
         try {
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(bos);

             oos.writeObject(this);
             ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
             ObjectInputStream ois = new ObjectInputStream(bis);
             return (ConcretePrototype)ois.readObject();
        }catch (Exception e){
             e.printStackTrace();
             return null;
        }
    }
 }/<string>/<code>

來看客戶端調用代碼:

<code> public class Client {
     public static void main(String[] args) {
         //創建原型對象
         ConcretePrototype prototype = new ConcretePrototype();
         prototype.setAge(18);
         prototype.setName("Tom");
         List<string> hobbies = new ArrayList<string>();
         hobbies.add("書法");
         hobbies.add("美術");
         prototype.setHobbies(hobbies);
 ​
         //拷貝原型對象
         ConcretePrototype cloneType = prototype.deepClone();
         cloneType.getHobbies().add("技術控");
 ​
         System.out.println("原型對象:" + prototype);
         System.out.println("克隆對象:" + cloneType);
         System.out.println(prototype == cloneType);
 ​
         System.out.println("原型對象的愛好:" + prototype.getHobbies());
         System.out.println("克隆對象的愛好:" + cloneType.getHobbies());
         System.out.println(prototype.getHobbies() == cloneType.getHobbies());
    }
 }/<string>/<string>/<code>

運行程序,我們發現得到了我們期望的結果:

<code> 原型對象:ConcretePrototype(age=18, name=Tom, hobbies=[書法, 美術])
 克隆對象:ConcretePrototype(age=18, name=Tom, hobbies=[書法, 美術, 技術控])

 false
 原型對象的愛好:[書法, 美術]
 克隆對象的愛好:[書法, 美術, 技術控]
 false/<code>

5.7.克隆破壞單例模式

如果我們克隆的目標的對象是單例對象,那意味著,深克隆就會破壞單例。實際上防止克隆破壞單 例解決思路非常簡單,禁止深克隆便可。要麼你我們的單例類不實現 Cloneable 接口;要麼我們重寫 clone()方法,在clone方法中返回單例對象即可,具體代碼如下:

<code> @Override
 protected Object clone() throws CloneNotSupportedException {
     return INSTANCE;
 }/<code>

5.8.原型模式在源碼中的應用

先來JDK中Cloneable接口:

<code> public interface Cloneable {
 }/<code>

接口定義還是很簡單的,我們找源碼其實只需要找到看哪些接口實現了 Cloneable 即可。來看 ArrayList類的實現。

Object方法

<code> protected native Object clone() throws CloneNotSupportedException;/<code>

ArrayList是實現的clone方法

<code> public class ArrayList 
extends AbstractList
         implements List, RandomAccess, Cloneable, java.io.Serializable
 {
     public Object clone() {
         try {
             ArrayList> v = (ArrayList>) super.clone();
             v.elementData = Arrays.copyOf(elementData, size);
             v.modCount = 0;
             return v;
        } catch (CloneNotSupportedException e) {
             // this shouldn't happen, since we are Cloneable
             throw new InternalError(e);
        }
    }
 }
/<code>

我們發現方法中只是將List中的元素循環遍歷了一遍。這個時候我們再思考一下,是不是這種形式 就是深克隆呢?其實用代碼驗證一下就知道了,繼續修改 ConcretePrototype 類,增加一個 deepCloneHobbies()方法:

<code> @Data
 public class ConcretePrototype implements Cloneable,Serializable {
    ...
     public ConcretePrototype deepCloneHobbies(){
         try {
             ConcretePrototype result = (ConcretePrototype)super.clone();
             result.hobbies = (List)((ArrayList)result.hobbies).clone();
             return result;
        } catch (CloneNotSupportedException e) {
             e.printStackTrace();
             return null;
        }
    }
    ...
 }/<code>

修改客戶端代碼:

<code> public class Client { 

     public static void main(String[] args) {
        ...
         //拷貝原型對象
         ConcretePrototype cloneType = prototype.deepCloneHobbies();
  ...
    }
 }/<code>

運行也能得到期望的結果。但是這樣的代碼,其實是硬編碼,如果在對象中聲明瞭各種集合類型, 那每種情況都需要單獨處理。因此,深克隆的寫法,一般會直接用序列化來操作。

5.9.原型模式的優缺點

優點:

1、性能優良,Java自帶的 原型模式 是基於內存二進制流的拷貝,比直接new一個對象性能上提 升了許多。

2、可以使用深克隆方式保存對象的狀態,使用原型模式將對象複製一份並將其狀態保存起來,簡化 了創建對象的過程,以便在需要的時候使用(例如恢復到歷史某一狀態),可輔助實現撤銷操作。

缺點:

1、需要為每一個類配置一個克隆方法。

2、克隆方法位於類的內部,當對已有類進行改造的時候,需要修改代碼,違反了開閉原則。

3、在實現深克隆時需要編寫較為複雜的代碼,而且當對象之間存在多重嵌套引用時,為了實現深克 隆,每一層對象對應的類都必須支持深克隆,實現起來會比較麻煩。因此,深拷貝、淺拷貝需要運用得 當。

6.0總結

克隆方式:1.序列化 反序列化 2.jsonobject 3淺克隆加賦值

淺克隆:繼承Cloneable接口的都是淺克隆。

深克隆兩種方式:序列化,轉JSON。

6.建造者模式

6.1.定義

建造者模式(Builder Pattern)是將一個複雜對象的構建過程與它的表示分離,使得同樣的構建過 程可以創建不同的表示,屬於創建型模式。使用建造者模式對於用戶而言只需指定需要建造的類型就可 以獲得對象,建造過程及細節不需要了解。

官方原文:Separate the construction of a complex object from its representation so that the same construction process can create different representations.

建造者模式適用於創建對象需要很多步驟,但是步驟的順序不一定固定。如果一個對象有非常複雜 的內部結構(很多屬性),可以將複雜對象的創建和使用進行分離。先來看一下建造者模式的類圖:

四、原型模式與建造者模式詳解

建造者模式的設計中主要有四個角色:

1、產品(Product):要創建的產品類對象

2、建造者抽象(Builder):建造者的抽象類,規範產品對象的各個組成部分的建造,一般由子類 實現具體的建造過程。

3、建造者(ConcreteBuilder):具體的Builder類,根據不同的業務邏輯,具體化對象的各個組成 部分的創建。

4、調用者(Director):調用具體的建造者,來創建對象的各個部分,在指導者中不涉及具體產品 的信息,只負責保證對象各部分完整創建或按某種順序創建。

6.2.建造者模式的應用場景

建造者模式適用於一個具有較多的零件的複雜產品的創建過程,由於需求的變化,組成這個複雜產 品的各個零件經常猛烈變化,但是它們的組合方式卻相對穩定。

  1. 相同的方法,不同的執行順序,產生不同的結果時
  2. 多個部件或零件,都可以裝配到一個對象中,但是產生的結果又不相同。
  3. 產品類非常複雜,或者產品類中的調用順序不同產生不同的作用。
  4. 當初始化一個對象特別複雜,參數多,而且很多參數都具有默認值時。

建造者模式,只關注用戶需要什麼,將最少的關鍵字傳過來,生成你想要的結果。

實際順序是在build方法裡面。那是順序和條件都確定了。每個順序和條件都分別存儲下來了。判斷有沒有,有就添加到product後面。當然就是先判斷條件再判斷order順序了

6.3.建造者模式的基本寫法

我們還是以課程為例,一個完整的課程需要由PPT課件、回放視頻、課堂筆記、課後作業組成,但 是這些內容的設置順序可以隨意調整,我們用建造者模式來代入理解一下。首先我們創建一個需要構造 的產品類Course:

<code> @Data
 public class Course {
     private String name;
     private String ppt;
     private String video;
     private String note;
     private String homework;
 }/<code>

然後創建建造者類CourseBuilder,將複雜的構造過程封裝起來,構造步驟由用戶決定:

<code> public class CourseBuilder{
 ​
     private Course course = new Course();
 ​
     public void addName(String name) {
         course.setName(name);
    }
     
     public void addPPT(String ppt) {
         course.setPpt(ppt);
    }
     
     public void addVideo(String video) {
         course.setVideo(video);
    }
     
     public void addNote(String note) {
         course.setNote(note);
    }
     
     public void addHomework(String homework) {
         course.setHomework(homework);
    }
     
     public Course build() {
         return course;
    }
 }/<code>

編寫測試類:

<code> public class Test {
     public static void main(String[] args) {
         CourseBuilder builder = new CourseBuilder();
         builder.addName("設計模式");
         builder.addPPT("【PPT課件】");
         builder.addVideo("【回放視頻】");
         builder.addNote("【課堂筆記】");
         builder.addHomework("【課後作業】");
         System.out.println(builder.build());
    }
 }/<code>

運行結果:

<code> Course(name=設計模式, ppt=【PPT課件】, video=【回放視頻】, note=【課堂筆記】, homework=【課後作業】)/<code> 

來看一下類結構圖:

四、原型模式與建造者模式詳解

6.4.建造者模式的鏈式寫法

在平時的應用中,建造者模式通常是採用鏈式編程的方式構造對象,下面我們來一下演示代碼,修 改CourseBuilder類,將Course變為CourseBuilder的內部類。然後,將構造步驟添加進去,每完成一個步驟,都返回this:

<code> public class CourseBuilder {
     private Course course = new Course();
 ​

     public CourseBuilder addName(String name) {
         course.setName(name);
         return this;
    }
 ​
     public CourseBuilder addPPT(String ppt) {
         course.setPpt(ppt);
         return this;
    }
 ​
     public CourseBuilder addVideo(String video) {
         course.setVideo(video);
         return this;
    }
 ​
     public CourseBuilder addNote(String note) {
         course.setNote(note);
         return this;
    }
 ​
     public CourseBuilder addHomework(String homework) {
         course.setHomework(homework);
         return this;
    }
 ​
     public Course build() {
         return this.course;
    }
 ​
     @Data
     public class Course {
         private String name;
         private String ppt;
         private String video;
         private String note;
         private String homework;
    }
 }/<code>

客戶端使用:

<code> public class Test {
     public static void main(String[] args) {
         CourseBuilder builder = new CourseBuilder()
                    .addName("設計模式")
                    .addPPT("【PPT課件】")
                    .addVideo("【回放視頻】")
                    .addNote("【課堂筆記】")

                    .addHomework("【課後作業】");
         System.out.println(builder.build());
    }
 }/<code>

這樣寫法是不是很眼熟,好像在哪見過呢?後面我們分析建造者模式在源碼中的應用大家就會明白。 接下來,我們再來看一下類圖的變化:

四、原型模式與建造者模式詳解

6.5.建造者模式應用案例

下面我們再來看一個實戰案例,這個案例參考了開源框架JPA的SQL構造模式。是否記得我們在構 造SQL查詢條件的時候,需要根據不同的條件來拼接SQL字符串。如果查詢條件複雜的時候,我們SQL 拼接的過程也會變得非常複雜,從而給我們的代碼維護帶來非常大的困難。因此,我們用建造者類 QueryRuleSqlBuilder 將複雜的構造 SQL 過程進行封裝,用 QueryRule 對象專門保存 SQL 查詢時的 條件,最後根據查詢條件,自動生成SQL語句。來看代碼,先創建QueryRule類:

<code> /**
  * QueryRule,主要功能用於構造查詢條件
  */
 public final class QueryRule implements Serializable
 {
  ...
  /**
  * 添加升序規則
  * @param propertyName
  * @return
  */
  public QueryRule addAscOrder(String propertyName) {
  this.ruleList.add(new Rule(ASC_ORDER, propertyName));
  return this;
  }
     
     public QueryRule andEqual(String propertyName, Object value) {
  this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(AND));
  return this;
  }
     
     public QueryRule andLike(String propertyName, Object value) {
  this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(AND));
  return this;
  }
  ...
 }/<code>

然後,創建QueryRuleSqlBuilder類:

<code> /**
  * 根據QueryRule自動構建sql語句
  */
 public class QueryRuleSqlBuilder {
  ...  
    /**
     * 處理like
     * @param rule
     */
    private  void processLike(QueryRule.Rule rule) {
       if (ArrayUtils.isEmpty(rule.getValues())) {
          return;
      }
       Object obj = rule.getValues()[0];
 ​
       if (obj != null) {

          String value = obj.toString();
          if (!StringUtils.isEmpty(value)) {
             value = value.replace('*', '%');
             obj = value;
          }
      }
       add(rule.getAndOr(),rule.getPropertyName(),"like","%"+rule.getValues()[0]+"%");
    }
     
     /**
  * 處理 =
  * @param rule
  */
  private  void processEqual(QueryRule.Rule rule) {
  if (ArrayUtils.isEmpty(rule.getValues())) {
  return;
  }
  add(rule.getAndOr(),rule.getPropertyName(),"=",rule.getValues()[0]);
  }
     
     /**
  * 處理 order by
  * @param rule 查詢規則
  */
  private void processOrder(Rule rule) {
  switch (rule.getType()) {
  case QueryRule.ASC_ORDER:
  // propertyName非空
  if (!StringUtils.isEmpty(rule.getPropertyName())) {
  orders.add(Order.asc(rule.getPropertyName()));
  }
  break;
  case QueryRule.DESC_ORDER:
  // propertyName非空
  if (!StringUtils.isEmpty(rule.getPropertyName())) {
  orders.add(Order.desc(rule.getPropertyName()));
  }
  break;
  default:
  break;
  }
  }
  ...
 }/<code>

創建Order類:

<code> /**
  * sql排序組件

  */
 public class Order {
    private boolean ascending; //升序還是降序
    private String propertyName; //哪個字段升序,哪個字段降序
   
    public String toString() {
       return propertyName + ' ' + (ascending ? "asc" : "desc");
    }
 ​
    /**
     * Constructor for Order.
     */
    protected Order(String propertyName, boolean ascending) {
       this.propertyName = propertyName;
       this.ascending = ascending;
    }
 ​
    /**
     * Ascending order
     *
     * @param propertyName
     * @return Order
     */
    public static Order asc(String propertyName) {
       return new Order(propertyName, true);
    }
 ​
    /**
     * Descending order
     *
     * @param propertyName
     * @return Order
     */
    public static Order desc(String propertyName) {
       return new Order(propertyName, false);
    }
 }/<code>

編寫測試代碼:

<code> public class Test {
     public static void main(String[] args) {
         QueryRule queryRule = QueryRule.getInstance();
         queryRule.addAscOrder("age");
         queryRule.andEqual("addr","Changsha");
         queryRule.andLike("name","Tom");
         QueryRuleSqlBuilder builder = new QueryRuleSqlBuilder(queryRule);
         System.out.println(builder.builder("t_member"));

         System.out.println("Params: " + Arrays.toString(builder.getValues()));
    }
 }/<code>

這樣一來,我們的客戶端代碼就非常清朗,來看運行結果:

<code> select * from t_member where  addr = ?  and name like ?  order by age asc
 Params: [Changsha, %Tom%]/<code>

6.6.建造者模式在源碼中的體現

下面來看建造者模式在哪些源碼中有應用呢?首先來看JDK的StringBuilder,它提供append()方 法,給我們開放構造步驟,最後調用toString()方法就可以獲得一個構造好的完整字符串,源碼如下:

<code> public final class StringBuilder
     extends AbstractStringBuilder
     implements java.io.Serializable, CharSequence
 {
     public StringBuilder append(StringBuffer sb) {
         super.append(sb);
         return this;
    }
 }/<code>

在MyBatis中也有體現,比如CacheBuilder類。

同樣在 MyBatis 中,比如 SqlSessionFactoryBuilder 通過調用 build()方法獲得的是一個 SqlSessionFactory 類。

當然,在 Spring中自然也少不了,比如 BeanDefinitionBuilder 通過調用getBeanDefinition()方法獲得一個BeanDefinition對象。

6.7.建造者模式的優缺點

建造者模式的優點:

1、封裝性好,創建和使用分離;

2、擴展性好,建造類之間獨立、一定程度上解耦。

建造者模式的缺點:

1、產生多餘的Builder對象;

2、產品內部發生變化,建造者都要修改,成本較大。

6.8.建造者模式和工廠模式的區別

建造者模式和工廠模式的區別

1、建造者模式更加註重方法的調用順序,工廠模式注重於創建對象。

2、創建對象的力度不同,建造者模式創建複雜的對象,由各種複雜的部件組成,工廠模式創建出來 的都一樣。

3、關注重點不一樣,工廠模式模式只需要把對象創建出來就可以了,而建造者模式中不僅要創建出 這個對象,還要知道這個對象由哪些部件組成。

4、建造者模式根據建造過程中的順序不一樣,最終的對象部件組成也不一樣。

可以理解為工廠創建過程是靜態的,構建者模式創建過程經過外放而變成動態的。

6.9.總結

四、原型模式與建造者模式詳解

7.0.作業

1.用JSON方式實現一個原型模式的深克隆,並畫出UML圖。

一行代碼,比IO流簡單。

<code> public ConcretePrototype deepCloneByJSON(){
     try {
         return JSON.parseObject(JSON.toJSONString(this), ConcretePrototype.class);

    }catch (Exception e){
         e.printStackTrace();
         return null;
    }
 }/<code>
四、原型模式與建造者模式詳解

2.請列舉1-3個需要用到建造者模式的業務場景。

建造者模式:適用於對象創建需要動態拼接複雜屬性值的業務場景。

例如:SQL拼接,鏈式編程,NIO,StringBuilder.append()方法。


分享到:


相關文章: