以小說的筆法寫的設計模式系列文章,你絕對看得懂![首發於公衆號:"聊聊代碼"]javascript
設計模式系列·王小二需求歷險記(一)
設計模式系列·王小二需求歷險記(二)
設計模式系列·封裝、繼承、多態
設計模式系列·初探設計模式之王小二的疑問
設計模式系列·Facade模式之MVC的煩惱
設計模式系列·Adapter 模式之如何優雅的使用別人的輪子
設計模式系列·類爆炸之Bridge模式
設計模式系列·工廠方法模式之 Code Review
設計模式系列·抽象工廠模式php
------華麗的分割線:正文開始------java
公司最近項目不忙,午間小憩以後,小二找到C哥攀談了起來。設計模式
"C哥,忙啥呢?"
"也沒忙啥,就是隨便看看。"函數
"哦哦,我最近也不怎麼忙。你上次給我講的工廠模式,受益不淺啊!"
"哈哈,是嘛!其實你不知道,還有抽象工廠模式呢!"post
"抽象工廠模式?願聞其詳。"
"好,反正最近也不忙,就給你講講吧。"spa
"小二,你知道,奧迪A4與A6,他們使用的輪胎與燈泡是不同的。"
"是,型號不同,輪胎與燈泡確定不同。"設計
"假設如今須要製造A4與A6的輪胎和燈泡,你會怎麼寫代碼?"
"這個嘛,好寫!"3d
小二熟練的打開電腦,揮斥方遒,迅速的寫出了代碼。code
<?php
class Client{
//根據不一樣型號生產不一樣輪胎
public function produce_wheel($type){
switch ($type){
case 'A4':
$obj=new AudiA4Wheel();
break;
case 'A6':
$obj=new AudiA6Wheel();
break;
default:
throw new Exception('no instance found');
}
$obj->produce_wheel();
}
//根據不一樣型號生產不一樣燈泡
public function produce_light($type){
switch ($type){
case 'A4':
$obj=new AudiA4Light();
break;
case 'A6':
$obj=new AudiA6Light();
break;
default:
throw new Exception('no instance found');
}
$obj->produce_light();
}
}
$client=new Client();
$client->produce_wheel('A4');
$client->produce_light('A4');複製代碼
"C哥,大致就是這麼個思路。您看看對嗎?"
"嗯,這代碼確實也實現了功能,可是,有問題。"
"有問題?什麼問題?"
"你這代碼存在着低內聚、高耦合的問題,很差維護啊。"
"怎麼低內聚、高耦合了?"小二一臉茫然。
C哥鎮定自若的解釋道:
好比,如今我要增長奧迪的型號A8,那你代碼裏的函數produce_wheel()
與produce_light()
是否是都要改?也就是這兩個函數是相互依賴的,不可能用A6的輪子,而用A8的燈泡。相互依賴,是爲高耦合。
produce_wheel()
與 produce_light()
函數,這兩個函數都關心本身須要什麼型號的產品,而且都負責把相應的產品生產出來。也就是,他有兩個職責:關心型號、根據不一樣型號生產出對應的產品。但這兩個職責是毫無關聯的,沒有半毛錢的關係。職責過多且分散,是爲低內聚。
"C哥這麼一說,還真是這麼回事。"
"哈哈,低內聚高耦合的代碼也能實現需求,可是這樣的代碼很差維護。"
"嗯嗯,C哥,有啥好辦法嗎?"
"固然有了,咱們這裏就用到了抽象工廠模式。"
"根據我多年的經驗,出現switch語句的地方,每每意味着須要抽象、或者存在着放錯責任的地方。"
"寶貴的經驗,記下了!"
"小二,其實這裏,就是放錯了責任。"
"嗯,怎麼說呢?"
"Client端既關心如何建立對象,又關心如何用對象來製造輪子、燈泡。"
"是,他的責任太多了。"
"其實,Client端只負責使用對象製造相關產品就好了。他不用負責創造對象。創造對象,交給Client端來作,就是放錯了責任。"
"對,確實是這樣。"
"還記得前幾天給你講的工廠模式嗎?工廠模式也是爲了解決這個問題。"
"記得記得,工廠模式也是爲了實現責任的分離。"
"工廠模式針對一種產品提供一個工廠類,而抽象工廠模式是針對一組相關或相互依賴的產品提供一個工廠類。"
"那抽象工廠模式就是工廠模式的升級版本啦!"
"是的。在這裏,Client端負責向Factory發出請求,Factory返回相關對象,Client端再根據Factory返回的對象,製造相關的產品。"
"也就是Client負責使用對象,Factory負責建立對象!"
"是的,小二很聰明嘛!看看抽象工廠模式的類圖吧!"
"好的,C哥。"
"小二啊,跟你講了這麼多,接下來就看你了!"
"好的C哥,我立刻畫出類圖、寫出代碼。"
小二仿照着C哥的類圖,又畫出了用抽象工廠解決上面問題的類圖。
<?php
//燈泡產品接口
interface Light{
public function produce_light(); } //奧迪A4燈泡產品 class AudiA4Light implements Light{
public function produce_light() {
echo "AudiA4 Light produced!\n";
}
}
//奧迪A6燈泡產品
class AudiA6Light implements Light{
public function produce_light() {
echo "AudiA6 Light produced!\n";
}
}
//輪子產品接口
interface Wheel{
public function produce_wheel(); } //奧迪A4輪子 class AudiA4Wheel implements Wheel {
public function produce_wheel() {
echo "AudiA4 Wheel produced!\n";
}
}
//奧迪A6輪子
class AudiA6Wheel implements Wheel {
public function produce_wheel() {
echo "AudiA6 Wheel produced!\n";
}
}
//工廠接口
interface Factory{
public function CreateWheel(); public function CreateLight(); } //奧迪A4工廠 class A4Factory implements Factory {
public function CreateWheel() {
return new AudiA4Wheel();
}
public function CreateLight() {
return new AudiA4Light();
}
}
//奧迪A6工廠
class A6Factory implements Factory {
public function CreateWheel() {
return new AudiA6Wheel();
}
public function CreateLight() {
return new AudiA6Light();
}
}
//客戶端調用類
class Client{
//運行主函數
public static function main($type){
$reflection=new ReflectionClass($type.'Factory');
$factory=$reflection->newInstance();
self::run($factory);
}
//生產產品
public static function run(Factory $factory){
$wheel=$factory->CreateWheel();
$wheel->produce_wheel();
$light=$factory->CreateLight();
$light->produce_light();
}
}
Client::main('A6');複製代碼
"嗯嗯,小二不錯嘛。簡單工廠、工廠方法、抽象工廠模式,你都掌握了。"
"哈哈,感謝C哥的教導!"
"恭喜你在設計模式打怪升級的道路上,再次斬獲新技能!"
聽到這句話,小二內心美滋滋的,嘴角露出了得意的微笑......
轉載聲明:本文轉載自「聊聊代碼」,搜索「talkpoem」便可關注。
關注「聊聊代碼」,讓咱們一塊兒聊聊「左手代碼右手詩」的事兒。