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

前言

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

建造者模式

簡介

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

這裏用一個示例來進行說明。
咱們一天吃的食物有這些,煎餅、盒飯、拉麪、豆漿、牛奶和果汁。分爲三餐、早餐、午飯和晚餐,餐點主要包含吃的(俗稱飯)和喝的(豆漿,果汁之類的),那麼咱們能夠把煎餅和豆漿做爲早餐,盒飯和果汁做爲午飯,這樣咱們能夠清楚的知道要吃早餐和午飯包含什麼食物。設計模式

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

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,用來建立一份餐點。至於建立的是什麼餐點,它不用知道,這一點由調用者來進行決定。測試

這裏咱們就能夠定義一個飯店,能夠建立一份餐點,建立什麼餐點有顧客決定。
代碼示例:ui

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

建立完成這個Director以後,咱們再來進行調用測試。this

代碼示例:.net

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 原創不易,轉載請標明出處,謝謝!

相關文章
相關標籤/搜索