編程中的設(shè)計(jì)模式之工廠模式

介紹

工廠模式(Factory Pattern)屬于設(shè)計(jì)模式中的創(chuàng)建型模式鲁豪,它提供了一種創(chuàng)建對(duì)象的最佳方式纹份。定義一個(gè)創(chuàng)建對(duì)象的接口溯饵,通過子類來完成對(duì)象的實(shí)例化,代碼層面只提供實(shí)例化類的名稱痛倚,無需關(guān)心實(shí)例化的過程,降低業(yè)務(wù)代碼和創(chuàng)建對(duì)象的耦合澜躺。工廠模式又分為三種模式蝉稳,簡(jiǎn)單工廠模式、工廠方法模式掘鄙、抽象工廠模式耘戚。

簡(jiǎn)單工廠模式

模擬一個(gè)業(yè)務(wù)使用場(chǎng)景,現(xiàn)在要根據(jù)文件后綴來設(shè)置不同的處理方法操漠,比如后綴為 .doc 的文件和后綴為 .xlsx 的文件都需要用 handleFile 方法處理收津,可以定義一個(gè)接口 File 在里邊規(guī)定 handleFile 方法,代碼示例如下:

<?php
interface File
{
  public function handleFile();
}

class DocFile implements File
{
  public function handleFile()
  {
    echo 'doc 文件的處理方式';
  }
}

class XlsxFile implements File
{
  public function handleFile()
  {
    echo 'xlxs 文件的處理方式';
  }
}
//創(chuàng)建工廠類,通過調(diào)用靜態(tài)方法完成類的實(shí)例化
class ChooseFile
{
  public static function createDoc()
  {
    return new DocFile();
  }

  public static function createXlxs()
  {
    return new XlsxFile();
  }
}
//調(diào)用 Doc 文件的處理方法
$doc = ChooseFile::createDoc();
$doc->handleFile();
//調(diào)用 Xlxs 文件的處理方法
$xlxs = ChooseFile::createXlxs();
$xlxs->handleFile();

通過這個(gè)例子可以看到朋截,根據(jù)客戶端的選擇蛹稍,可以實(shí)例化不同的類,可以使業(yè)務(wù)代碼和接口完成解耦部服,但是該模式違反了面向?qū)ο缶幊淘瓌t中的 開放封閉原則(Open Closed Principle) 唆姐,并且只有一個(gè)工廠類負(fù)責(zé)所有方法的實(shí)現(xiàn),如果后期需要擴(kuò)展廓八,只能修改工廠類奉芦,靜態(tài)方法也無法繼承,注定了該模式只適合實(shí)例化類少或是較為簡(jiǎn)單的應(yīng)用場(chǎng)景剧蹂。

關(guān)于開放封閉原則的知識(shí)補(bǔ)充

該原則的是面向?qū)ο缶幊痰暮诵模?strong>對(duì)擴(kuò)展開放声功,對(duì)修改封閉。軟件需求總是會(huì)發(fā)生變化的宠叼,對(duì)應(yīng)用的擴(kuò)展是軟件設(shè)計(jì)必須考慮的先巴,減少對(duì)類的修改可以增強(qiáng)類的獨(dú)立性,降低代碼之間的耦合冒冬。在上邊的例子中伸蚯,ChooseFile 提供一個(gè)對(duì)客戶端的訪問接口,是一個(gè)已完成的類简烤,如果需要引入其他的文件處理方式剂邮,就需要修改這個(gè)工廠類,這就違反了“對(duì)修改封閉”的原則横侦。

工廠方法模式

常說的工廠模式挥萌,其實(shí)就是該模式,因?yàn)榻鉀Q了簡(jiǎn)單工廠模式中的開放封閉原則的問題枉侧,擴(kuò)展更加方便引瀑,所以使用最多。還以上邊提到的應(yīng)用場(chǎng)景為例棵逊,我們現(xiàn)在如果要加入新的文件格式 .php 伤疙,通過改造工廠類,定義接口辆影,具體的類實(shí)例化工作由子類完成徒像,如果需要添加擴(kuò)展,就新增文件處理的擴(kuò)展類和工廠子類示蛙讥,例如下:

<?php
interface File
{
  public function handleFile();
}

class DocFile implements File
{
  public function handleFile()
  {
    echo 'doc 文件的處理方式';
  }
}

class XlsxFile implements File
{
  public function handleFile()
  {
    echo 'xlxs 文件的處理方式';
  }
}
//新增PHP文件的處理類
class PhpFile implements File
{
  public function handleFile()
  {
    echo 'PHP 文件的處理方式';
  }
}

//創(chuàng)建工廠接口锯蛀,由子類實(shí)現(xiàn)接口的方法
interface CreateFile
{
  public function getInstance();
}

class CreateDoc implements CreateFile
{
  public function getInstance()
  {
    return new DocFile();
  }
}

class CreateXlsx implements CreateFile
{
  public function getInstance()
  {
    return new XlsxFile();
  }
}

class CreatePhp implements CreateFile
{
  public function getInstance()
  {
    return new PhpFile();
  }
}
//doc
$doc = new CreateDoc();
$docFile = $doc->getInstance();
$docFile->handleFile();
//xlsx
$xlsx = new CreateXlsx();
$xlsxFile = $doc->getInstance();
$xlsxFile ->handleFile();
//php
$php = new CreatePhp();
$phpFile = $php->getInstance();
$phpFile ->handleFile();

工廠方法模式解決了開閉原則的問題,擴(kuò)展不需要修改原有代碼次慢,但是增加越多的文件處理方式旁涤,就需要同步增加相應(yīng)的文件處理類和工廠子類翔曲,類的數(shù)量增加會(huì)帶來系統(tǒng)復(fù)雜度的提升。

抽象工廠模式

相比工廠方法模式劈愚,該模式進(jìn)一步對(duì)代碼進(jìn)行了抽象瞳遍,通過接口的形式對(duì)產(chǎn)品進(jìn)行歸納約束,并再通過抽象類組合多種產(chǎn)品菌羽,形成完整的對(duì)象掠械,如下例子:
1.先是定義了文件接口 TextFile、系統(tǒng)接口 System注祖;
2.再對(duì)每個(gè)接口具體實(shí)現(xiàn) DocFile 猾蒂、XlsxFile 、Windows 是晨、Mac 肚菠;
3.定義抽象類 AbstractFactory,描述文件類和系統(tǒng)類的關(guān)系罩缴;
4.再對(duì)抽象類具體實(shí)現(xiàn) WinFile 蚊逢、MacFile;
5.創(chuàng)建類的構(gòu)造器 FactoryFile->getFactory()箫章;
6.工廠輸出產(chǎn)品时捌。

<?php
//定義文件接口
interface TextFile
{
    public function read();
    public function write();
}
//Doc文件處理類的具體實(shí)現(xiàn)
class DocFile implements TextFile
{
    public function read()
    {
        echo 'doc read';
    }

    public function write()
    {
        echo 'doc write';
    }
}
//Xlsx文件處理類的具體實(shí)現(xiàn)
class XlsxFile implements TextFile
{
    public function read()
    {
        echo 'xlsx read';
    }

    public function write()
    {
        echo 'xlsx write';
    }
}
//系統(tǒng)接口定義
interface System
{
    public function upload();
}
//windows 系統(tǒng)類具體實(shí)現(xiàn)
class Windows implements System
{
    public function upload()
    {
        echo '上傳到 Windows';
    }
}
//Mac 系統(tǒng)類具體實(shí)現(xiàn)
class Mac implements System
{
    public function upload()
    {
        echo '上傳到 Mac OS';
    }
}
//定義抽象類,描述文件和系統(tǒng)的關(guān)系
abstract class AbstractFactory
{
    abstract public function getFile($fileType);
    abstract public function getSystem($systemType);
}
//windows 操作系統(tǒng)的抽象類實(shí)現(xiàn)
class WinFile extends AbstractFactory
{
    public function getFile($fileType)
    {
        return new $fileType;
    }

    public function getSystem($systemType)
    {
        return new $systemType;
    }
}
//Mac 操作系統(tǒng)的抽象類實(shí)現(xiàn)
class MacFile extends AbstractFactory
{
    public function getFile($fileType)
    {
        return new $fileType;
    }

    public function getSystem($systemType)
    {
        return new $systemType;
    }
}
//實(shí)例化抽象類的子類
class FactoryFile
{
    public function getFactory($factory)
    {
        return new $factory;
    }
}
//測(cè)試類
class Client
{
    public function getInfo()
    {
        $factoryFile = new FactoryFile();
        $winFactory = $factoryFile->getFactory('WinFile');
        $docFile = $winFactory->getFile('DocFile');
        $docFile->read();
        $docFile->write();
        $system = $winFactory->getSystem('Windows');
        $system->upload();
    }
}

$client = new Client();
$client->getInfo();

抽象工廠模式是三種模式里最難理解的一種炉抒,并且該模式的擴(kuò)展會(huì)違反開閉原則,它適合用來描述工廠中多產(chǎn)品之間的關(guān)聯(lián)稚叹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末焰薄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子扒袖,更是在濱河造成了極大的恐慌塞茅,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件季率,死亡現(xiàn)場(chǎng)離奇詭異野瘦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)飒泻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門鞭光,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泞遗,你說我怎么就攤上這事惰许。” “怎么了史辙?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵汹买,是天一觀的道長(zhǎng)佩伤。 經(jīng)常有香客問我,道長(zhǎng)晦毙,這世上最難降的妖魔是什么生巡? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮见妒,結(jié)果婚禮上孤荣,老公的妹妹穿的比我還像新娘。我一直安慰自己徐鹤,他們只是感情好垃环,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著返敬,像睡著了一般遂庄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上劲赠,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天涛目,我揣著相機(jī)與錄音,去河邊找鬼凛澎。 笑死霹肝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的塑煎。 我是一名探鬼主播沫换,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼最铁!你這毒婦竟也來了讯赏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤冷尉,失蹤者是張志新(化名)和其女友劉穎漱挎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雀哨,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡磕谅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雾棺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膊夹。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖捌浩,靈堂內(nèi)的尸體忽然破棺而出割疾,到底是詐尸還是另有隱情,我是刑警寧澤嘉栓,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布宏榕,位于F島的核電站拓诸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏麻昼。R本人自食惡果不足惜奠支,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抚芦。 院中可真熱鬧倍谜,春花似錦、人聲如沸叉抡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褥民。三九已至季春,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間消返,已是汗流浹背载弄。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撵颊,地道東北人宇攻。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像倡勇,于是被迫代替她去往敵國和親逞刷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349