設(shè)計(jì)模式——建造者模式

builder

閱讀原文請?jiān)L問我的博客BrightLoong's Blog

一. 概述

建造者模式(Builder)弧岳,又叫生成器模式,它將一個(gè)復(fù)雜對象的構(gòu)建與它的表示分離涧卵,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示腹尖。

建造者模式可以將一個(gè)產(chǎn)品的內(nèi)部表象與產(chǎn)品的生成過程分割開來热幔,使用建造者模式,用戶就只需指定需要建造的類型就可以得到它們近尚,二具體建造的過程和細(xì)節(jié)就不需要知道了肿男。

建造者模式相比于工廠模式更加關(guān)注組成部分的裝配細(xì)節(jié)和順序却嗡。

創(chuàng)建者模式屬于創(chuàng)建型模式嘹承。

二. UML類圖解析

建造者模式的UML類圖如下:

builder
  • Builder:為創(chuàng)建一個(gè)Product對象的各個(gè)部件指定的抽象接口叹卷,buildPart()是對象組成部分構(gòu)造的抽象方法,根據(jù)需求可以有多個(gè)組成部分的構(gòu)造方法往毡。
  • ConcreteBuilder:具體建造者靶溜,繼承自Builder,構(gòu)造和裝配各個(gè)部件嗤详,getResult()返回構(gòu)造后的實(shí)例葱色。
  • Director:指揮者娘香,持有一個(gè)Builder引用,調(diào)用具體的創(chuàng)建者的各個(gè)部件來創(chuàng)建對象舞痰,負(fù)責(zé)保證對象各部分完整創(chuàng)建或者按某種順序創(chuàng)建 响牛。
  • Product:產(chǎn)品赫段,要創(chuàng)建的具體對象糯笙,一般來說是一個(gè)復(fù)雜的對象,包含多個(gè)組成部分豺憔。

三. 代碼實(shí)現(xiàn)

這里把電腦作為一個(gè)產(chǎn)品够庙,一般來說一個(gè)可以使用的臺式電腦包括顯示器耘眨、主機(jī)、鍵盤和鼠標(biāo)胆屿,各個(gè)組成部分可以有不同的品牌、性能环鲤、型號等細(xì)節(jié)冷离,下面就使用建造者模式來對電腦進(jìn)行實(shí)現(xiàn)唇兑。

產(chǎn)品類——Computer

package io.github.brightloong.design.builder;

/**
 * 產(chǎn)品類Computer,為了方便實(shí)現(xiàn)蔫耽,所有組成均用String來表示匙铡。
 * Created by BrightLoong on 2018/5/24.
 */
public class Computer {
    /**
     * 顯示器
     */
    public String displayer;

    /**
     * 主機(jī)
     */
    public String host;

    /**
     * 鍵盤
     */
    public String keyboard;

    /**
     * 鼠標(biāo)
     */
    public String mouse;

    public String getDisplayer() {
        return displayer;
    }

    public void setDisplayer(String displayer) {
        this.displayer = displayer;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getKeyboard() {
        return keyboard;
    }

    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }

    public String getMouse() {
        return mouse;
    }

    public void setMouse(String mouse) {
        this.mouse = mouse;
    }

    /**
     * 覆蓋toString方法.
     * @return
     */
    @Override
    public String toString() {
        return "Computer{" +
                "displayer='" + displayer + '\'' +
                ", host='" + host + '\'' +
                ", keyboard='" + keyboard + '\'' +
                ", mouse='" + mouse + '\'' +
                '}';
    }
}

構(gòu)建抽象——ComputerBuilder

package io.github.brightloong.design.builder;

/**
 * Created by BrightLoong on 2018/5/24.
 */
public abstract class ComputerBuilder {
    abstract void buildDisplay();
    abstract void buildHost();
    abstract void buildKeyBoard();
    abstract void buildMouse();
    abstract Computer getComputer();
}

具體構(gòu)建類——SuperComputerBuilder

package io.github.brightloong.design.builder;

/**
 * Created by BrightLoong on 2018/5/24.
 */
public class SuperComputerBuilder extends ComputerBuilder {
    Computer computer;

    public SuperComputerBuilder() {
        computer = new Computer();
    }

    void buildDisplay() {
        computer.setDisplayer("37.5英寸顯示器IPS曲面屏微邊框防眩光4K屏幕");
    }

    void buildHost() {
        computer.setHost("i7-6950X/TiTANX 高端硬管水冷電腦六核游戲主機(jī)");
    }

    void buildKeyBoard() {
        computer.setKeyboard("猛禽競技機(jī)械鍵盤");
    }

    void buildMouse() {
        computer.setMouse("逆天懸浮鼠標(biāo)");
    }

    Computer getComputer() {
        return computer;
    }
}

指揮者——ComputerDirector

package io.github.brightloong.design.builder;

/**
 * Created by BrightLoong on 2018/5/24.
 */
public class ComputerDirector {
    private ComputerBuilder computerBuilder;

    public ComputerDirector(ComputerBuilder computerBuilder) {
        this.computerBuilder = computerBuilder;
    }

    public Computer build() {
        computerBuilder.buildDisplay();
        computerBuilder.buildHost();
        computerBuilder.buildKeyBoard();
        computerBuilder.buildMouse();
        return computerBuilder.getComputer();
    }
}

客戶端調(diào)用和輸出

package io.github.brightloong.design.builder;

/**
 * Created by BrightLoong on 2018/5/24.
 */
public class Client {
    public static void main(String[] args) {
        Computer computer = new ComputerDirector(new SuperComputerBuilder()).build();
        System.out.println(computer);
    }
}

輸出:

Computer{displayer='37.5英寸顯示器IPS曲面屏微邊框防眩光4K屏幕', host='i7-6950X/TiTANX 高端硬管水冷電腦六核游戲主機(jī)', keyboard='猛禽競技機(jī)械鍵盤', mouse='逆天懸浮鼠標(biāo)'}

四. 總結(jié)

使用場景

  • 用于創(chuàng)建一些復(fù)雜的對象嚼摩,這些對象內(nèi)部構(gòu)建的順序通常是穩(wěn)定的,但對象內(nèi)部的構(gòu)建通常面臨著復(fù)雜的變化愿卒。
  • 當(dāng)創(chuàng)建復(fù)雜的對象的算法應(yīng)該獨(dú)立于該對象的組成部分已經(jīng)它們的裝配方法時(shí)琼开。

優(yōu)點(diǎn)

  • 建造者模式使得建造代碼與表示代碼分離,隱藏了產(chǎn)品實(shí)現(xiàn)細(xì)節(jié)枕荞。
  • 如果要改變一個(gè)產(chǎn)品的內(nèi)部表示柜候,只要再定義一個(gè)具體的建造者就可以了,方便擴(kuò)展躏精。
  • 建造者模式通過指揮者可以控制組件建造順序渣刷,能實(shí)現(xiàn)一定程度的細(xì)節(jié)把控,特別是那種生成的產(chǎn)品對象之間存在屬性依賴的情況玉控。

缺點(diǎn)

  • 如果產(chǎn)品多變飞主,會生成大量的建造類,造成類膨脹高诺。

五. 擴(kuò)展——構(gòu)建器

在《Effective Java》一書中碌识,第2條提到:

遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮用構(gòu)建器虱而。

當(dāng)有多個(gè)參數(shù)的時(shí)候筏餐,客戶端代碼不僅難編寫,也很難閱讀牡拇,再有魁瞪,客戶端可能不清楚每個(gè)參數(shù)到底代表什么。

這里也使用到了Builder模式惠呼,不直接生成想要的對象导俘,二是讓客戶端利用所有必要的參數(shù)調(diào)用Builder構(gòu)造器,得到一個(gè)builder對象剔蹋。然后客戶端在builder對象上調(diào)用類似于setter的方法旅薄,來設(shè)置每個(gè)相關(guān)的可選參數(shù)。最后泣崩,客戶端調(diào)用無參的build方法來生成不可變(相比較JavaBeans模式少梁,也就是調(diào)用set方法來進(jìn)行設(shè)值,這種方式可以生成不可變對象)的對象矫付。下面的是具體的代碼凯沪,來自《Effective Java》書上的列子。

package io.github.brightloong.design.builder;

/**
 * Created by BrightLoong on 2018/5/24.
 */
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        //Required parameters
        private final int servingSize;
        private final int servings;

        //Optional parameters - initialized to default values
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int val) {
            calories = val;
            return this;
        }

        public Builder fat(int val) {
            fat = val;
            return this;
        }

        public Builder sodium(int val) {
            sodium = val;
            return this;
        }

        public Builder carbohydrate(int val) {
            carbohydrate = val;
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }

    }

    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }

    @Override
    public String toString() {
        return "NutritionFacts{" +
                "servingSize=" + servingSize +
                ", servings=" + servings +
                ", calories=" + calories +
                ", fat=" + fat +
                ", sodium=" + sodium +
                ", carbohydrate=" + carbohydrate +
                '}';
    }
}

調(diào)用和輸出:

package io.github.brightloong.design.builder;

/**
 * Created by BrightLoong on 2018/5/24.
 */
public class Client2 {
    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts.Builder(240,8)
                .calories(100).sodium(35)
                .carbohydrate(27)
                .build();
        System.out.println(cocaCola);
    }
}

輸出:

NutritionFacts{servingSize=240, servings=8, calories=100, fat=0, sodium=35, carbohydrate=27}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末买优,一起剝皮案震驚了整個(gè)濱河市妨马,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杀赢,老刑警劉巖烘跺,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異葵陵,居然都是意外死亡液荸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門脱篙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娇钱,“玉大人,你說我怎么就攤上這事绊困∥穆В” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵秤朗,是天一觀的道長煤蹭。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么硝皂? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任常挚,我火速辦了婚禮,結(jié)果婚禮上稽物,老公的妹妹穿的比我還像新娘奄毡。我一直安慰自己,他們只是感情好贝或,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布吼过。 她就那樣靜靜地躺著,像睡著了一般咪奖。 火紅的嫁衣襯著肌膚如雪盗忱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天羊赵,我揣著相機(jī)與錄音趟佃,去河邊找鬼。 笑死慷垮,一個(gè)胖子當(dāng)著我的面吹牛揖闸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播料身,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼汤纸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芹血?” 一聲冷哼從身側(cè)響起贮泞,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎幔烛,沒想到半個(gè)月后啃擦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饿悬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年令蛉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狡恬。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡珠叔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出弟劲,到底是詐尸還是另有隱情祷安,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布兔乞,位于F島的核電站汇鞭,受9級特大地震影響凉唐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜霍骄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一台囱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腕巡,春花似錦玄坦、人聲如沸血筑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豺总。三九已至车伞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喻喳,已是汗流浹背另玖。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留表伦,地道東北人谦去。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像蹦哼,于是被迫代替她去往敵國和親鳄哭。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容