設(shè)計(jì)模式之工廠模式

開個新坑涨颜,復(fù)習(xí)基礎(chǔ)知識,用typescript寫寫舊技術(shù)——設(shè)計(jì)模式依沮。今天就介紹一下工廠模式涯贞,以及其他兩個衍生模式工廠方法抽象工廠枪狂。

簡單工廠

工廠模式,又稱簡單工廠宋渔,顧名思義就是使用“工廠”(一個或一系列方法)去生產(chǎn)“產(chǎn)品”(一個或一系列的派生類實(shí)例)州疾。UML如下所示:

Simple Factory

上圖我定義產(chǎn)品接口名為Vegetable,它的兩個派生類為Onion和Garlic:

// Vegetable.ts
interface Vegetable {
  fry(): void;
}

class Onion implements Vegetable {
  public fry(): void {
      console.log('Onion');
  }
}

class Garlic implements Vegetable {
  public fry(): void {
      console.log('Garlic');
  }
}

“蔬菜工廠”如下所示皇拣,通過調(diào)用不同的方法生產(chǎn)出不同的蔬菜實(shí)例严蓖。

p.s. 有些工廠模式的實(shí)現(xiàn)只有一個函數(shù)體,根據(jù)特定參數(shù)來“生產(chǎn)”特定的派生實(shí)例审磁,這也是可行的谈飒。

// SimpleFactory.ts
import {Garlic, Onion, Vegetable} from './Vegetable';

class SimpleFactory {
  public createOnion(): Vegetable {
    return new Onion();
  }

  public createGarlic(): Vegetable {
    return new Garlic();
  }
}

最后看一下client調(diào)用:

// client.ts
import {SimpleFactory} from './SimpleFactory';
import {Vegetable} from './Vegetable';

const factory: SimpleFactory = new  SimpleFactory();

let onion: Vegetable = factory.createOnion();
let garlic: Vegetable = factory.createGarlic();

onion.fry(); // Onion
garlic.fry(); // Garlic

OK,問題來了态蒂,我們使用工廠模式的意義是什么杭措?饒了這么一大圈不就是打印了個兩個菜名嗎?為什么不直接new呢钾恢?

import {Onion, Garlic} from './Vegetable';

let onion: Onion = new Onion();
let garlic: Garlic = new Garlic();

直接new出兩個蔬菜實(shí)力確實(shí)特別簡單手素,但是在大型軟件開發(fā)中這很危險(xiǎn),用專業(yè)術(shù)語來說是違反了依賴倒置原則

高層模塊不應(yīng)該依賴于低層模塊瘩蚪,二者都應(yīng)該依賴于抽象泉懦;抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象

有點(diǎn)繞疹瘦,陽春白雪和者必寡崩哩,我們還是走下里巴人路線吧。通俗來講言沐,引入的依賴并不可靠邓嘹,它一般是第三方庫或是其他開發(fā)人員實(shí)現(xiàn)的代碼;在不確定的某一天险胰,里面的代碼會被修改甚至是刪除汹押。這時(shí)候你的代碼會變得很脆,不知不覺中就崩了起便。但現(xiàn)實(shí)中又不可能不引入其他依賴棚贾,所以大家就約定最小依賴引入:依賴提供者將隱藏對象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對外公開接口(抽象)榆综,這就是OOP三大特性之一的封裝妙痹。

再回看一下client實(shí)現(xiàn),只import了一個公用接口Vegetable鼻疮。運(yùn)行時(shí)细诸,我們利用多態(tài)——let onion: Vegetable = factory.createOnion()——就可以實(shí)現(xiàn)派生方法的動態(tài)綁定(onion.fry())。這樣陋守,“派生蔬菜”(Onion或Garlic)的修改就不會影響現(xiàn)有代碼了震贵。哪天VegetableFactory開發(fā)者覺得Onion子類實(shí)現(xiàn)太過丑陋或是性能太差,他只需在簡單工廠里換一個新的“派生蔬菜”(OnionFromJapan)即可水评,client代碼不需要做任何改動猩系。

class VegetableFactory {
 public createOnion(): Vegetable {
   return new OnionFromJapan();
 }
}

工廠模式的最大優(yōu)點(diǎn)就是屏蔽產(chǎn)品的具體實(shí)現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口中燥。當(dāng)然寇甸,它也有自己的問題,產(chǎn)品種類可能有成千上萬疗涉,如果都是依靠同一個工廠生產(chǎn)拿霉,那么必然會使得工廠代碼及其龐大。這就有了工廠方法的設(shè)計(jì)實(shí)現(xiàn)咱扣。

工廠方法

工廠方法就是針對每一種產(chǎn)品提供一個工廠類绽淘,通過不同派生工廠創(chuàng)建不同的產(chǎn)品。

Factory Method

實(shí)現(xiàn)很簡單闹伪,為每種蔬菜提供對應(yīng)的派生“蔬菜工廠”就行了沪铭。問題又來了,工廠與蔬菜一一對應(yīng)有沒有多此一舉呢偏瓤?要不直接new杀怠?嗯,這里不給出解答了厅克,回去體會一下oop三大特性:封裝赔退、多態(tài)和繼承

import {Garlic, Onion, Vegetable} from './Vegetable';

interface VegetableFactory {
  create(): Vegetable;
}

class OnionFactory implements VegetableFactory {
  public create(): Vegetable {
    return new Onion();
  }
}

class GarlicFactory implements VegetableFactory {
  public create(): Vegetable {
    return new Garlic();
  }
}

工廠方法減輕了工廠類的負(fù)擔(dān)证舟,新增一種“蔬菜”只需添加一個特定的“蔬菜工廠”即可硕旗,這就符合了開放閉合原則

對擴(kuò)展是開放的;對修改是關(guān)閉的

這里提一下褪储,開放閉合原則并不是說接口一成不變卵渴,它要求的是增量變化——只增加新方法,不改動舊方法鲤竹。

抽象工廠

工廠方法自然比簡單工廠更加靈活浪读,但當(dāng)業(yè)務(wù)有所變更時(shí),比如需要添加“蔬菜”的周邊產(chǎn)品——“酒”呢辛藻?(洋蔥和紅酒更配哦)這時(shí)候我們就需要一個更復(fù)雜的模式——抽象工廠了碘橘。

Abstract Factory

抽象工廠是一個產(chǎn)品簇的概念,一個工廠可以生產(chǎn)多種業(yè)務(wù)相關(guān)的產(chǎn)品吱肌。我們在工廠方法的基礎(chǔ)上擴(kuò)充一下代碼:定義一個抽象工廠接口AbstractFactory痘拆,通過不同的方法生產(chǎn)出一個“抽象”產(chǎn)品簇(VegetableDrink)〉回過頭來再看工廠方法纺蛆,事實(shí)上它就是抽象工廠最簡單的一種場景設(shè)計(jì)——只生成一種產(chǎn)品吐葵。

interface AbstractFactory {
  create(): Vegetable;
  pick(): Drink;
}

class OnionRecipe implements AbstractFactory {
  public create(): Vegetable {
    return new Onion();
  }

  public pick(): Drink {
    return new Wine();
  }
}

抽象工廠的缺點(diǎn)很明顯:成也產(chǎn)品簇?cái)∫伯a(chǎn)品簇,復(fù)雜度大桥氏,應(yīng)用場景有限温峭。

總結(jié)

  • 簡單工廠:調(diào)用者只需使用單例工廠就可獲取同一范疇的所有產(chǎn)品

  • 工廠方法:調(diào)用者并不知道它在運(yùn)行時(shí)會獲取何種產(chǎn)品,只知道某個特定的工廠能生成出滿足需求的產(chǎn)品

  • 抽象工廠:調(diào)用者可以在運(yùn)行時(shí)從特定的工廠中獲得所有信息相關(guān)的產(chǎn)品簇

設(shè)計(jì)模式是上個世紀(jì)九十年代初從建筑領(lǐng)域引入到計(jì)算機(jī)軟件開發(fā)領(lǐng)域的概念字支;是對軟件設(shè)計(jì)中反復(fù)出現(xiàn)的各種問題所提出的一套解決方案凤藏。一般來說,設(shè)計(jì)模式的教學(xué)案例都是基于OOP語言java實(shí)現(xiàn)的堕伪,所以有時(shí)候會有一種錯覺揖庄,以為設(shè)計(jì)模式只有java開發(fā)人員才該掌握的。但事實(shí)上設(shè)計(jì)模式更多的是一種思想欠雌,是在某種情景下解決特定問題的可靠途徑蹄梢,它不僅僅局限于組織編碼,更可以應(yīng)用于架構(gòu)層面的思考桨昙。

思考題

如果我們的一個服務(wù)類中出現(xiàn)大量類似于if(useA)检号、if(useB)這樣的條件判斷語句,你會怎么去重構(gòu)它蛙酪?


class Service {
  public methodA(): void {
    ...
    if( this.useA ){
        // omit
    }

    ...
  }

  public methodB(): void {
    ...
    if( this.useA ){
        // omit
    }
    ...

    if( this.useB ){
      // omit
    }
    ...
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末齐苛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子桂塞,更是在濱河造成了極大的恐慌凹蜂,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阁危,死亡現(xiàn)場離奇詭異玛痊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)狂打,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門擂煞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人趴乡,你說我怎么就攤上這事对省。” “怎么了晾捏?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵蒿涎,是天一觀的道長。 經(jīng)常有香客問我惦辛,道長劳秋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮玻淑,結(jié)果婚禮上嗽冒,老公的妹妹穿的比我還像新娘。我一直安慰自己岁忘,他們只是感情好辛慰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著干像,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驰弄。 梳的紋絲不亂的頭發(fā)上麻汰,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機(jī)與錄音戚篙,去河邊找鬼五鲫。 笑死,一個胖子當(dāng)著我的面吹牛岔擂,可吹牛的內(nèi)容都是我干的位喂。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼乱灵,長吁一口氣:“原來是場噩夢啊……” “哼塑崖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起痛倚,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤规婆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蝉稳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抒蚜,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年耘戚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗡髓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡收津,死狀恐怖饿这,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情朋截,我是刑警寧澤蛹稍,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站部服,受9級特大地震影響唆姐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜廓八,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一奉芦、第九天 我趴在偏房一處隱蔽的房頂上張望赵抢。 院中可真熱鬧,春花似錦声功、人聲如沸烦却。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽其爵。三九已至,卻和暖如春伸蚯,著一層夾襖步出監(jiān)牢的瞬間摩渺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工剂邮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摇幻,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓挥萌,卻偏偏與公主長得像绰姻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子引瀑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評論 2 350

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