Java進階篇設計模式之三 ----- 建造者模式和原型模式

來源:互聯網
上載者:User
前言

在上一篇中我們學習了原廠模式,介紹了簡單原廠模式、Factory 方法和抽象原廠模式。本篇則介紹設計模式中屬於建立型模式的建造者模式和原型模式。

建造者模式簡介

建造者模式是屬於建立型模式。建造者模式使用多個簡單的對象一步一步構建成一個複雜的對象。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。
簡單的來說就是將一個複雜的東西抽離出來,對外提供一個簡單的調用,可以在同樣的構建過程建立不同的表示。和原廠模式很相似,不過相比而言更加註重組件的裝配。

這裡用一個樣本來進行說明。
我們一天吃的食物有這些,煎餅、便當、拉麵、豆漿、牛奶和果汁。分為三餐、早餐、午餐和晚餐,餐點主要包含吃的(俗稱飯)和喝的(豆漿,果汁之類的),那麼我們可以把煎餅和豆漿作為早餐,便當和果汁作為午餐,這樣我們可以清楚的知道要吃早餐和午餐包含什麼食物。

首先我們定義一個食物類,有兩個屬性,吃的和喝的。

class Meal{    private String food;    private String drinks;        public String getFood() {        return food;    }    public void setFood(String food) {        this.food = food;    }        public String getDrinks() {        return drinks;    }    public void setDrinks(String drinks) {        this.drinks = drinks;    }}

定義了食物時候,我們在定義一個食物的標準介面,一份食物包含什麼,其實也就是吃的和喝的。

interface IBuilderFood{    void buildFood();    void buildDrinks();    Meal createMeal();}

食物介面定義一個吃的和一個喝的組件,然後通過createMeal()方法返回我們需要的食物。
那麼現在我們便可以定義一份早餐和午餐。
程式碼範例:

class Breakfast implements IBuilderFood{    Meal meal;    public Breakfast(){        meal=new Meal();    }        @Override    public void buildFood() {        meal.setFood("煎餅");    }    @Override    public void buildDrinks() {        meal.setDrinks("豆漿");       }        @Override    public Meal createMeal() {        return meal;    }}class Lunch implements IBuilderFood{    Meal meal;    public Lunch(){        meal=new Meal();    }        @Override    public void buildFood() {        meal.setFood("便當");    }    @Override    public void buildDrinks() {        meal.setDrinks("果汁");       }        @Override    public Meal createMeal() {        return meal;    }}

定義完之後,建造早餐和午餐的的過程已經完畢了。但是這並不是建造者模式,它有個核心的Director(導演者),它用來建立複雜物件的部分,對該部分進行完整的建立或者按照一定的規則進行建立。那麼這裡我們可以建立一個Director,用來建立一份餐點。至於建立的是什麼餐點,它不用知道,這一點由調用者來進行決定。

這裡我們就可以定義一個飯店,可以建立一份餐點,建立什麼餐點有顧客決定。
程式碼範例:

class FoodStore{    public Meal createBreakfast(IBuilderFood bf){        bf.buildDrinks();        bf.buildFood();        return bf.createMeal();    }}

建立完成這個Director之後,我們再來進行調用測試。

程式碼範例:

public class BuilderTest {    public static void main(String[] args) {        FoodStore foodStore=new FoodStore();        Meal meal=foodStore.createBreakfast(new Breakfast());        Meal meal2=foodStore.createBreakfast(new Lunch());        System.out.println("小明早上吃的是:"+meal.getFood()+",喝的飲料是:"+meal.getDrinks());        System.out.println("小明中午吃的是:"+meal2.getFood()+",喝的飲料是:"+meal2.getDrinks());     }}

輸出結果:

小明早上吃的是:煎餅,喝的飲料是:豆漿小明中午吃的是:便當,喝的飲料是:果汁

簡單的介紹了下建造者模式的運作原理,可以概況為這4點:

  1. Builder:指定一個抽象的介面,規定該產品所需實現組件的建立,並不涉及具體的對象組件的建立。

  2. ConcreteBuilder:需實現Builder介面,並且針對不同的邏輯,進行不同方法的建立,最終提供該產品的執行個體。

  3. Director:用來建立複雜物件的部分,對該部分進行完整的建立或者按照一定的規則進行建立。

  4. Product:示被構造的複雜物件。

使用情境:
適用一些基本組件不便,但是組合經常變化的時候。比如超市促銷的大禮包。

優點:

  1. 建造者獨立,易擴充。
  2. 便於控制細節風險。

缺點

  1. 內部結構複雜,不易於理解。
  2. 產品直接需要有共同點,範圍有控制。
原型模式

原型模式(Prototype Pattern)是用於建立重複的對象,同時又能保證效能。這種類型的設計模式屬於建立型模式,它提供了一種建立對象的最佳方式。

一般來說我們在建立對象的時候是直接建立的,但是建立該對象的代價很大的時候,重複的二次建立就有些不划算,這時我們就可以使用原型模式。
打個比方,我們都發送過郵件,在節日的時候一般發送的是祝福語句,在這些祝福語句中,一般除了名字不一樣之外,大部分都是一樣的。這時我們就可以利用該模式來進行相應出建立。

這裡還是用一個的簡單的樣本來說明。
小明和小紅在同一天生日,然後我們需要給他們發送郵件進行祝福,但是由於比較懶,祝福語除了名字之外都是一樣的。這時我們就可以先完成祝福語的編寫,然後複製該祝福語,最後根據不同的名稱進行發送。不過這裡就從簡了,只是簡單的列印下而已。

程式碼範例:

public class PrototypeTest {    public static void main(String[] args) {        Mail mail=new Mail();        mail.setMsg("生日快樂!");        Mail mail2=(Mail) mail.clone();        mail.setName("小明");        mail2.setName("小紅");        System.out.println(mail.toString());        System.out.println(mail2.toString());    }} class Mail implements Cloneable {    private String name;    private String msg;        public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }    public Object clone() {        Object clone = null;        try {            clone = super.clone();        } catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return clone;    }    @Override    public String toString() {        return name + ":" + msg ;    }    }

輸出結果:

小明:生日快樂!小紅:生日快樂!

看完原型模式的建立,是不是感覺就是和Java中複製即為類似呢?
實際上它的核心也就是複製。
複製有兩種,淺複製和深複製,本文主要介紹的是淺複製。
淺複製:

在淺複製中,如果原型對象的成員變數是實值型別,將複製一份給複製對象;如果原型對象的成員變數是參考型別,則將引用對象的地址複製一份給複製對象,也就是說原型對象和複製對象的成員變數指向相同的記憶體位址。
簡單來說,在淺複製中,當對象被複製時只複製它本身和其中包含的實值型別的成員變數,而參考型別的成員對象並沒有複製。
實現Cloneable介面並重寫Object類中的clone()方法;

深複製:

在深複製中,無論原型對象的成員變數是實值型別還是參考型別,都將複製一份給複製對象,深複製將原型對象的所有引用對象也複製一份給複製對象。

簡單來說,在深複製中,除了對象本身被複製外,對象所包含的所有成員變數也將複製。
實現Serializable介面,通過對象的序列化和還原序列化實現複製,可以實現真正的深度複製。

使用情境:

  1. 類初始化的時候需要消耗大量資源的時候;
  2. 擷取資料庫連接繁瑣的時候;
  3. 一個對象,有很多個修改者的時候;

優點:
1.可以提升效能;

缺點:
1.因為必須實現Cloneable 介面,所以用起來可能不太方便。

其它音樂推薦

原創不易,如果感覺不錯,希望給個推薦!您的支援是我寫作的最大動力!
著作權聲明:
虛無境
部落格園出處:http://www.cnblogs.com/xuwujing
CSDN出處:http://blog.csdn.net/qazwsxpcm    
個人部落格出處:http://www.panchengming.com
原創不易,請標明出處,謝謝!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.