設(shè)計(jì)模式之工廠模式(為什么很多人覺得工廠模式?jīng)]有用)

前言

隨著編程技術(shù)的不斷發(fā)展周蹭,面向?qū)ο笳Z言和面向?qū)ο蟪绦蛟O(shè)計(jì)逐漸成為主流绰筛。這就不可避免地涉及到了對象的創(chuàng)建。創(chuàng)建一個(gè)對象逐工,并使用已經(jīng)定義好的方法铡溪,看起來也很清晰和簡單。有的時(shí)候泪喊,在不同的情況下需要不同子類的對象棕硫,如何降低耦合度、方便地進(jìn)行切換袒啼,而不需要將所有實(shí)例化該對象的地方都進(jìn)行修改哈扮,則涉及到了模式纬纪。

下面將依次介紹簡單工廠模式、工廠方法模式滑肉、抽象工廠模式包各,說明他們是如何實(shí)現(xiàn)創(chuàng)建對象這一功能的。(后文將三者統(tǒng)稱為工廠模式靶庙。)

簡單工廠模式

一個(gè)很簡單的做法问畅,既然你說可能要使用不同的對象,那我將所有創(chuàng)建對象的操作都集中起來六荒,只在一個(gè)地方進(jìn)行對象的創(chuàng)建护姆,其他地方都通過這里來創(chuàng)建對象。以后即便要修改掏击,也只需要改一處地方不就可以了卵皂。

以生產(chǎn)鼠標(biāo)為例,我們需要有線鼠標(biāo)和無線鼠標(biāo)砚亭。則大致的代碼如下:

abstract class Mouse {
}

class WiredMouse : Mouse {
}

class WirelessMouse : Mouse {
}

class SimpleFactory_1 {
    public Mouse createMouse(String type) {
    if ("wired".equals(type)) {
        return new WiredMouse();  
    } else if ("wireless".equals(type)) {
      return new WirelessMouse();
    } else {
      // unknown type !
      return null;
    }
  }
}

簡單工廠模式十分簡單直觀灯变,代碼量也很少。這份代碼的一個(gè)改進(jìn)之處是將 createMouse 的參數(shù)從 String 類型改成枚舉類型捅膘,以免使用時(shí)拼寫錯(cuò)誤柒凉,也能更好地對參數(shù)進(jìn)行限制。

簡單工廠模式的缺點(diǎn)是篓跛,如果我們需要增加新的鼠標(biāo)膝捞,那么我們就必須修改 createMouse 方法,增加 if/else 語句愧沟。這樣就破壞了"對修改封閉"的原則蔬咬。

簡單工廠模式可以定義成靜態(tài)方法,也可以定義成實(shí)例方法沐寺。他們的特點(diǎn)如下:

  • 靜態(tài)方法
    • 無需創(chuàng)建對象就能使用
    • 不能使用繼承來改變創(chuàng)建方法的行為
  • 實(shí)例方法
    • 需要?jiǎng)?chuàng)建對象才能使用
    • 可以使用繼承來改變創(chuàng)建方法的行為

更進(jìn)一步林艘,假設(shè)有 A、B 兩家公司都生產(chǎn)有線和無線鼠標(biāo)混坞,他們的鼠標(biāo)定義如下:

// A 的鼠標(biāo)
class AWiredMouse : WiredMouse {
}

class AWirelessMouse : WirelessMouse {
}

// B 的鼠標(biāo)
class BWiredMouse : WiredMouse {
}

class BWirelessMouse : WirelessMouse {
}

對應(yīng)的簡單工廠模式代碼如下:

class SimpleFactory_2 {
    public Mouse createMouse(String factory, String type) {
    if ("A".equeals(factory)) {
      if ("wired".equals(type)) {
        return new AWiredMouse();  
      } else if ("wireless".equals(type)) {
        return new AWirelessMouse();
      } else {
        // unknown type !
        return null;
      }  
    } else if ("B".equals(factory)) {
      if ("wired".equals(type)) {
        return new BWiredMouse();  
      } else if ("wireless".equals(type)) {
        return new BWirelessMouse();
      } else {
        // unknown type !
        return null;
      }
    } else {
      // unknown factory !
      return null;
    }
  }
}

可以看到代碼開始復(fù)雜起來了狐援,如果還有更多公司 C、D 也在生產(chǎn)鼠標(biāo)究孕,或者有更多的鼠標(biāo)類型啥酱,那么這個(gè)工廠類將會(huì)更將復(fù)雜。

工廠方法模式

下面我們就來看看工廠方法模式是如何處理這種問題厨诸。

abstract class Factory {
    public Mouse CreateMouse(String type);
}

class AFactory_2 : Factory {
  public Mouse CreateMouse(String type) {
    if ("wired".equals(type)) {
      return new AWiredMouse();  
    } else if ("wireless".equals(type)) {
      return new AWirelessMouse();
    } else {
      // unknown type !
      return null;
    } 
  }
}

class BFactory_2 : Factory {
  public Mouse CreateMouse(String type) {
    if ("wired".equals(type)) {
      return new BWiredMouse();  
    } else if ("wireless".equals(type)) {
      return new BWirelessMouse();
    } else {
      // unknown type !
      return null;
    } 
  }
}

可以看到镶殷,工廠方法模式中,定義了多個(gè)工廠類分別對應(yīng)各自的公司微酬,每個(gè)類只負(fù)責(zé)創(chuàng)建自己的鼠標(biāo)绘趋,而不用管其他公司的颤陶。

如果還有更多的公司,則定義新的工廠類即可陷遮,不需要修改已有的代碼滓走。

如果需要生產(chǎn)更多類型的鼠標(biāo),則需要對工廠都做修改帽馋,增加相應(yīng)的 if/else 語句來處理闲坎。這一點(diǎn)與簡單工廠模式類似。

工廠方法模式茬斧,體現(xiàn)了"對擴(kuò)展開發(fā),對修改封閉"梗逮。

這里為了說明使用工廠方法模式相比簡單工廠模式的優(yōu)點(diǎn)项秉,特意給鼠標(biāo)增加了公司(A、B)和類型(有線慷彤、無線)這兩個(gè)緯度娄蔼,以便說明工廠方法模式對代碼職責(zé)進(jìn)行劃分。

實(shí)際上底哗,對應(yīng)簡單工廠 SimpleFactory_1 也可以改成工廠方法模式岁诉,代碼如下:

abstract class Factory {
    public Mouse CreateMouse();
}

class WiredFactory_1 : Factory {
  public Mouse CreateMouse() {
    return new AWiredMouse();  
  }
}

class WirelessFactory_1 : Factory {
  public Mouse CreateMouse() {
     return new AWirelessMouse();
  }
}

抽象工廠模式

這些公司除了生產(chǎn)鼠標(biāo)外,還會(huì)生產(chǎn)鍵盤等產(chǎn)品跋选。鍵盤的定義如下:

abstract class Keyboard {
}

class WiredKeyboard : Keyboard {
}

class WirelessKeyboard : Keyboard {
}

// A
class AWiredKeyboard : WiredKeyboard {
}

class AWirelessKeyboard : WirelessKeyboard {
}

// B
class BWiredKeyboard : WiredKeyboard {
}

class BWirelessKeyboard : WirelessKeyboard {
}

對應(yīng)的抽象工廠模式如下:

abstract class Factory {
  public Mouse createMouse(String type);
  
  public Keyboard createKeyboard(String type);
}

class AFactory_2 : Factory {
  public Mouse createMouse(String type) {
    // 與之前一致
  }
  
  public Keyboard createKeyboard(String type) {
    if ("wired".equals(type)) {
      return new AWiredKeyboard();  
    } else if ("wireless".equals(type)) {
      return new AWirelessKeyboard();
    } else {
      // unknown type !
      return null;
    } 
  }
}

class BFactory_2 : Factory {
  public Mouse createMouse(String type) {
    // 與之前一致
  }
  
  public Keyboard createKeyboard(String type) {
    if ("wired".equals(type)) {
      return new BWiredKeyboard();  
    } else if ("wireless".equals(type)) {
      return new BWirelessKeyboard();
    } else {
      // unknown type !
      return null;
    } 
  }
}

可以看到:現(xiàn)在一個(gè)工廠會(huì)負(fù)責(zé)生產(chǎn)鼠標(biāo)涕癣、鍵盤等多種產(chǎn)品,并且每個(gè)工廠只負(fù)責(zé)自己的部分前标。

如果還有新的公司也可以生成鼠標(biāo)坠韩、鍵盤這些產(chǎn)品,則只需要添加新的工廠類即可炼列,無需修改已有的類只搁。

如果還要生產(chǎn)更多的產(chǎn)品比如顯示器等,則需要修改所有的工廠類俭尖。

這里的例子氢惋,工廠方法也可以拆成抽象工廠來表示。稽犁。

總結(jié)

簡單工廠模式的重點(diǎn)在于將創(chuàng)建產(chǎn)品的代碼統(tǒng)一在一處焰望,方便管理。

工廠方法模式已亥、抽象工廠模式除了將創(chuàng)建產(chǎn)品的代碼統(tǒng)一在一處柿估,還提供了一種便捷地更換產(chǎn)品系列的能力——當(dāng)我需要 A 公司的產(chǎn)品,那么就使用 AAFactory陷猫;當(dāng)我需要 B 公司的產(chǎn)品秫舌,那么就使用 BFactory的妖;只需要修改使用的工廠即可實(shí)現(xiàn)將所有的產(chǎn)品都改成對應(yīng)的產(chǎn)品,大大降低了耦合度和修改的成本足陨。

很多時(shí)候嫂粟,我們只需要用到簡單工廠模式就足夠了。但這并不是工廠方法模式墨缘、抽象工廠模式?jīng)]有用星虹,而是很多時(shí)候沒有這種需求——我們只需要一種類型的產(chǎn)品就足夠了,并不需要同時(shí)支持多種產(chǎn)品镊讼;在這種情況下宽涌,使用簡單工廠模式的確會(huì)更加簡單。

然而蝶棋,一旦我們同時(shí)需要不同類型的產(chǎn)品卸亮,那么簡單工廠模式就很容易使得方法體快速膨脹,使用工廠方法模式和抽象工廠模式可以更好地對代碼和職責(zé)進(jìn)行劃分玩裙。

工廠方法模式只生產(chǎn)一種產(chǎn)品兼贸,而抽象工廠模式則是生產(chǎn)一系列產(chǎn)品(,通常這些產(chǎn)品之間有一定聯(lián)系的)吃溅。抽象工廠模式生產(chǎn)其中的每個(gè)產(chǎn)品時(shí)溶诞,通常使用工廠方法模式。

參考

  • 《Head First 設(shè)計(jì)模式》

  • 《設(shè)計(jì)模式 可復(fù)用面向?qū)ο筌浖幕A(chǔ)》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末决侈,一起剝皮案震驚了整個(gè)濱河市螺垢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赖歌,老刑警劉巖甩苛,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異俏站,居然都是意外死亡讯蒲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進(jìn)店門肄扎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來墨林,“玉大人,你說我怎么就攤上這事犯祠⌒竦龋” “怎么了?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵衡载,是天一觀的道長搔耕。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么弃榨? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任菩收,我火速辦了婚禮,結(jié)果婚禮上鲸睛,老公的妹妹穿的比我還像新娘娜饵。我一直安慰自己,他們只是感情好官辈,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布箱舞。 她就那樣靜靜地躺著,像睡著了一般拳亿。 火紅的嫁衣襯著肌膚如雪晴股。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天肺魁,我揣著相機(jī)與錄音电湘,去河邊找鬼。 笑死万搔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的官帘。 我是一名探鬼主播瞬雹,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼刽虹!你這毒婦竟也來了酗捌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤涌哲,失蹤者是張志新(化名)和其女友劉穎胖缤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阀圾,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哪廓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了初烘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涡真。...
    茶點(diǎn)故事閱讀 38,687評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肾筐,靈堂內(nèi)的尸體忽然破棺而出哆料,到底是詐尸還是另有隱情,我是刑警寧澤吗铐,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布东亦,位于F島的核電站,受9級特大地震影響唬渗,放射性物質(zhì)發(fā)生泄漏典阵。R本人自食惡果不足惜奋渔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萄喳。 院中可真熱鬧卒稳,春花似錦、人聲如沸他巨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽染突。三九已至捻爷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間份企,已是汗流浹背也榄。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人算凿。 一個(gè)月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓昔期,卻偏偏與公主長得像,于是被迫代替她去往敵國和親囚霸。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評論 2 349

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

  • 前言 關(guān)于設(shè)計(jì)模式激才,是一個(gè)永遠(yuǎn)說不完的也說不清的話題拓型。畢竟在編程的世界里,沒有最好的設(shè)計(jì)模式瘸恼,只有最合適的設(shè)計(jì)模式...
    VV木公子閱讀 1,471評論 0 9
  • 工廠模式是我們最常用的實(shí)例化對象模式了劣挫,是用工廠方法代替new操作的一種模式。通常我們所說的工廠模式是指工廠方法模...
    zfylin閱讀 1,312評論 0 7
  • 文章部分內(nèi)容轉(zhuǎn)載自:http://blog.csdn.net/zhangerqing 一东帅、設(shè)計(jì)模式的分類 總體來說...
    j_cong閱讀 2,060評論 0 20
  • 這個(gè)例子在窮查理寶典中压固,被查理多次提到,但是靠闭,直到看到第399頁邓夕,他寫出來具體的解釋,我才明白這個(gè)諺語的意思: 3...
    記錄自己的文字閱讀 1,307評論 0 1
  • 最近一直在看書阎毅,現(xiàn)在看的是古典老師的第三本書焚刚,才看到第四部分,總共八個(gè)部分扇调,一千零六十二頁矿咕,但是實(shí)在是覺得讀起來像...
    蝸牛貝塔蜜閱讀 541評論 0 0