學(xué)好設(shè)計(jì)模式防被祭天:生成器模式

生成器模式

為了防止被“殺”了祭天瓤檐,學(xué)點(diǎn)設(shè)計(jì)模式,并總結(jié)下還是有必要的排截。

一:理解

  1. 生成器模式又名建造模式嫌蚤,是一種對(duì)象構(gòu)建模式。
  2. 生成器用于構(gòu)建較為復(fù)雜的對(duì)象断傲,可以將復(fù)雜對(duì)象的創(chuàng)建過程抽象出來脱吱。
  3. 例如生產(chǎn)一臺(tái)電腦,涉及到主板认罩、CPU箱蝠、硬盤等零配件的生產(chǎn),不同型號(hào)的電腦又需要不同的配件垦垂。電腦對(duì)象的構(gòu)造較復(fù)雜宦搬,適合使用生成器模式。
  4. 生成器模式抽象出一臺(tái)機(jī)器劫拗,操作者無需了解電腦A和電腦B的具體組裝過程间校,他只需來到生產(chǎn)電腦A的機(jī)器或生產(chǎn)電腦B的機(jī)器前,按下生產(chǎn)按鈕即可页慷。


二:例子

你是個(gè)富二代憔足。

你家有個(gè)汽車廠,你帶著小金鏈子大金表酒繁,開心得當(dāng)著你的廠長(zhǎng)滓彰。

汽車廠的生產(chǎn)流程代碼是程序員小王寫的。

其中州袒,汽車類如下:

@Data
public class Car {
    private Engine engine;
    private Headlight headlight;
    private Tyre tyre;

    public Car() {
    }

    public Car(Engine engine, Headlight headlight, Tyre tyre) {
        this.engine = engine;
        this.headlight = headlight;
        this.tyre = tyre;
    }

    public String toString() {
        return engine.getName() + " " + headlight.getName() + " " + tyre.getName();
    }
}

汽車類中包含三個(gè)屬性揭绑,分別是引擎,大燈和輪胎郎哭。

其中的零件類如下:

// 引擎類
@Data
public class Engine {
    private String name;
}

// 大燈類
@Data
public class Headlight {
    private String name;
}

// 輪胎類
@Data
public class Tyre {
    private String name;
}

為了方便舉例洗做,零件類只包含一個(gè)name屬性弓叛。

你家的汽車廠生產(chǎn)很多不同品牌的汽車,不然也沒法在你高貴的朋友圈里裝X诚纸。

為了方便,這里只例舉寶馬車和奔馳車陈惰。

寶馬車和奔馳車的生產(chǎn)過程沒什么區(qū)別畦徘,只是它們對(duì)應(yīng)的零件不一樣。

寶馬車對(duì)應(yīng)的零件為:寶馬引擎抬闯,寶馬大燈井辆,米其林輪胎。

奔馳車對(duì)應(yīng)的零件為:奔馳引擎溶握,奔馳大燈杯缺,米其林輪胎。

對(duì)應(yīng)的零件類如下:

// 寶馬引擎
@Data
public class BMWEngine extends Engine {
    public BMWEngine() {
        setName("寶馬引擎");
    }
}

// 寶馬大燈
@Data
public class BMWHeadlight extends Headlight {
    public BMWHeadlight() {
        setName("寶馬大燈");
    }
}

// 奔馳引擎
@Data
public class BenzEngine extends Engine {
    public BenzEngine() {
        setName("奔馳引擎");
    }
}

// 奔馳大燈
@Data
public class BenzHeadlight extends Headlight {
    public BenzHeadlight() {
        setName("奔馳大燈");
    }
}

// 米其林輪胎
@Data
public class MichelinTyre extends Tyre {
    public MichelinTyre() {
        setName("米其林輪胎");
    }
}

汽車廠員工各個(gè)都是精英睡榆,會(huì)所有品牌汽車的裝配方法萍肆。

例如,員工類中包含assembleBMW和assembleBenz方法胀屿。

兩個(gè)方法都新建一個(gè)Car對(duì)象塘揣,不同點(diǎn)在于傳入的零件不同。

public class Staff {
    public Car assembleBMW() {
        Car car = new Car(new BMWEngine(), new BMWHeadlight(), new MichelinTyre());
        return car;
    }

    public Car assembleBenz() {
        Car car = new Car(new BenzEngine(), new BenzHeadlight(), new MichelinTyre());
        return car;
    }
}

測(cè)試:

public class Client {
    public static void main(String[] args) {
        Staff staff = new Staff();
        System.out.println(staff.assembleBMW());
        System.out.println(staff.assembleBenz());
    }
}

你發(fā)現(xiàn)宿崭,assembleBMW和assembleBenz方法類似亲铡,是否可以只對(duì)外暴露一個(gè)方法assembleCar,具體零件參數(shù)由調(diào)用方傳入葡兑。傳入寶馬車所需零件奖蔓,就生產(chǎn)寶馬車。

畢竟你是高富帥讹堤,保持代碼清晰優(yōu)雅是有需要的吆鹤,這樣逼格比較高。

于是就在你的淫威之下蜕劝,將代碼進(jìn)行了重構(gòu)檀头,的確變得清晰了一些。

public class Staff {
    public Car assembleBMW(Engine engine, Headlight height, Tyre tyre) {
        Car car = new Car(engine, height, tyre);
        return car;
    }
}

隨著你廠的業(yè)績(jī)?cè)絹碓胶冕妫銣?zhǔn)備生產(chǎn)更多品牌的汽車暑始。

小王發(fā)現(xiàn),如果需要生產(chǎn)新品牌的汽車婴削,有兩種方案:

  1. 在Staff類中增加方法廊镜,例如assembleAudi,需要修改Staff類唉俗。
  2. 讓調(diào)用方自己傳不同零件參數(shù)嗤朴。

然而配椭,你廠生產(chǎn)的汽車品牌實(shí)在太多了。

調(diào)用方經(jīng)常容易搞混雹姊,導(dǎo)致造出半寶馬半奔馳車股缸。

半寶馬半奔馳車

于是,你把程序員小王殺了祭天吱雏。

生活還得繼續(xù)敦姻,你找來程序員小菜,詢問是否有比較優(yōu)雅的方式完成這個(gè)需求歧杏。

小菜經(jīng)過思考镰惦,覺得可以使用生成器模式來完成這個(gè)優(yōu)雅的需求。

  1. 新建出制造汽車的機(jī)器犬绒,即生成器旺入。
  2. 不同品牌的汽車對(duì)應(yīng)不同的生成器,例如寶馬生成器凯力,奔馳生成器等茵瘾。
  3. 需要生產(chǎn)新品牌汽車,只需新建新的生成器沮协。
  4. 調(diào)用方無需知道每種車的生產(chǎn)方法龄捡,只需調(diào)用生成器的方法即可。

小菜上來就是一頓敲慷暂。

為了約束不同品牌汽車生成器的步驟聘殖,他首先新建了一個(gè)抽象類。

public abstract class Builder {
    protected Car car;

    public abstract void assembleEngine();

    public abstract void assembleHeadlight();

    public abstract void assembleTyre();

    public Car createCar() {
        this.car = new Car();
        assembleEngine();
        assembleHeadlight();
        assembleTyre();
        return car;
    }
}

在這個(gè)抽象生成器中行瑞,包含Car屬性奸腺,和三個(gè)抽象方法,分別用于裝備引擎血久,裝配大燈和裝配輪胎突照。

此外有一個(gè)createCar方法,用于生成整輛汽車氧吐。

這里用到了模版方法模式讹蘑,將方法具體的實(shí)現(xiàn)延遲到子類。

小菜接著新建了寶馬汽車生成器和奔馳汽車生成器。

// 寶馬車生成器
public class BMWBuilder extends Builder {
    @Override
    public void assembleEngine() {
        car.setEngine(new BMWEngine());
    }

    @Override
    public void assembleHeadlight() {
        car.setHeadlight(new BMWHeadlight());
    }

    @Override
    public void assembleTyre() {
        car.setTyre(new MichelinTyre());
    }
}

// 奔馳車生成器
public class BenzBuilder extends Builder {
    @Override
    public void assembleEngine() {
        car.setEngine(new BenzEngine());
    }

    @Override
    public void assembleHeadlight() {
        car.setHeadlight(new BenzHeadlight());
    }

    @Override
    public void assembleTyre() {
        car.setTyre(new MichelinTyre());
    }
}

兩個(gè)生成器類,分別實(shí)現(xiàn)了抽象生成器中的抽象方法逛尚。

經(jīng)過重構(gòu)磅甩,員工類只需持有生成器對(duì)象和一個(gè)assembleCar方法扁达,該方法直接調(diào)用生成器的createCar方法。

@Data
public class StaffV2 {
    private Builder builder;

    public Car assembleCar() {
        return builder.createCar();
    }
}

員工類變得簡(jiǎn)單清晰介袜,好比就是員工只需來到生產(chǎn)汽車的機(jī)器面前痹兜,按下一個(gè)按鈕蛮粮,即可生產(chǎn)益缎。

測(cè)試:

public class ClientV2 {
    public static void main(String[] args) {
        StaffV2 staffV2 = new StaffV2();
        BMWBuilder bmwBuilder = new BMWBuilder();
        staffV2.setBuilder(bmwBuilder);
        Car bmwCar = staffV2.assembleCar();
        System.out.println(bmwCar);
        BenzBuilder benzBuilder = new BenzBuilder();
        staffV2.setBuilder(benzBuilder);
        Car benzCar = staffV2.assembleCar();
        System.out.println(benzCar);
    }
}

在使用生成器模式重構(gòu)之后,你的汽車廠變得非常靈活然想。

調(diào)用者再也不需要了解造車的具體流程莺奔,只需調(diào)用對(duì)應(yīng)生成器的一個(gè)方法即可。

你的汽車廠業(yè)績(jī)蒸蒸日上又沾,你也超級(jí)開心弊仪。

超開心


三:再理解

  1. 生成器模式可以通過建立抽象生成器來約束生產(chǎn)過程,具體過程可以延遲到子類實(shí)現(xiàn)杖刷。
  2. 在需要生成新類時(shí)候,只需新建一個(gè)生成器類驳癌,無需在員工代碼中增加方法滑燃。符合對(duì)修改關(guān)閉,對(duì)增加開放原則颓鲜。
  3. 生成器模式將帶有邏輯的對(duì)象新建過程留在服務(wù)層表窘,對(duì)調(diào)用者透明。
  4. 客戶端無須知道復(fù)雜對(duì)象的內(nèi)部組成部分與裝配方式甜滨,只需要知道所需建造者的類型即可乐严,做到客戶端和產(chǎn)品創(chuàng)建過程的解耦。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衣摩,一起剝皮案震驚了整個(gè)濱河市昂验,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌艾扮,老刑警劉巖既琴,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異泡嘴,居然都是意外死亡甫恩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門酌予,熙熙樓的掌柜王于貴愁眉苦臉地迎上來磺箕,“玉大人,你說我怎么就攤上這事抛虫∷擅遥” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵莱褒,是天一觀的道長(zhǎng)击困。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么阅茶? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任蛛枚,我火速辦了婚禮,結(jié)果婚禮上脸哀,老公的妹妹穿的比我還像新娘蹦浦。我一直安慰自己,他們只是感情好撞蜂,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布盲镶。 她就那樣靜靜地躺著,像睡著了一般蝌诡。 火紅的嫁衣襯著肌膚如雪溉贿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天浦旱,我揣著相機(jī)與錄音宇色,去河邊找鬼。 笑死颁湖,一個(gè)胖子當(dāng)著我的面吹牛宣蠕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甥捺,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼抢蚀,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了镰禾?” 一聲冷哼從身側(cè)響起皿曲,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎羡微,沒想到半個(gè)月后谷饿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妈倔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年博投,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盯蝴。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毅哗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捧挺,到底是詐尸還是另有隱情虑绵,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布闽烙,位于F島的核電站翅睛,受9級(jí)特大地震影響声搁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捕发,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一疏旨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扎酷,春花似錦檐涝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至凡纳,卻和暖如春窃植,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背荐糜。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工撕瞧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狞尔。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像巩掺,于是被迫代替她去往敵國(guó)和親偏序。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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