介紹
工廠模式(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)稚叹。