設計模式系列·抽象工廠模式

午後閒談

公司最近項目不忙,午間小憩以後,小二找到C哥攀談了起來。php

"C哥,忙啥呢?"
"也沒忙啥,就是隨便看看。"設計模式

"哦哦,我最近也不怎麼忙。你上次給我講的工廠模式,受益不淺啊!"
"哈哈,是嘛!其實你不知道,還有抽象工廠模式呢!"函數

"抽象工廠模式?願聞其詳。"
"好,反正最近也不忙,就給你講講吧。"spa

從奧迪車提及

"小二,你知道,奧迪A4與A6,他們使用的輪胎與燈泡是不同的。"
"是,型號不同,輪胎與燈泡確定不同。"設計

"假設如今須要製造A4與A6的輪胎和燈泡,你會怎麼寫代碼?"
"這個嘛,好寫!"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的燈泡。相互依賴,是爲高耦合。rem

produce_wheel()produce_light() 函數,這兩個函數都關心本身須要什麼型號的產品,而且都負責把相應的產品生產出來。也就是,他有兩個職責:關心型號、根據不一樣型號生產出對應的產品。但這兩個職責是毫無關聯的,沒有半毛錢的關係。職責過多且分散,是爲低內聚。

"C哥這麼一說,還真是這麼回事。"
"哈哈,低內聚高耦合的代碼也能實現需求,可是這樣的代碼很差維護。"

"嗯嗯,C哥,有啥好辦法嗎?"
"固然有了,咱們這裏就用到了抽象工廠模式。"

抽象工廠模式現身

"根據我多年的經驗,出現switch語句的地方,每每意味着須要抽象、或者存在着放錯責任的地方。"
"寶貴的經驗,記下了!"

"小二,其實這裏,就是放錯了責任。"
"嗯,怎麼說呢?"

"Client端既關心如何建立對象,又關心如何用對象來製造輪子、燈泡。"
"是,他的責任太多了。"

"其實,Client端只負責使用對象製造相關產品就好了。他不用負責創造對象。創造對象,交給Client端來作,就是放錯了責任。"
"對,確實是這樣。"

"還記得前幾天給你講的工廠模式嗎?工廠模式也是爲了解決這個問題。"
"記得記得,工廠模式也是爲了實現責任的分離。"

"工廠模式針對一種產品提供一個工廠類,而抽象工廠模式是針對一組相關或相互依賴的產品提供一個工廠類。"
"那抽象工廠模式就是工廠模式的升級版本啦!"

"是的。在這裏,Client端負責向Factory發出請求,Factory返回相關對象,Client端再根據Factory返回的對象,製造相關的產品。"
"也就是Client負責使用對象,Factory負責建立對象!"

"是的,小二很聰明嘛!看看抽象工廠模式的類圖吧!"
"好的,C哥。"

image_1bf1t96rn1e4vdp2tel1rlh5jom.png-70.7kB

用抽象工廠模式來解決問題

"小二啊,跟你講了這麼多,接下來就看你了!"
"好的C哥,我立刻畫出類圖、寫出代碼。"

小二仿照着C哥的類圖,又畫出了用抽象工廠解決上面問題的類圖。
image_1bf209bs589c10g919bb1g1ela61g.png-79.9kB
畫好類圖,代碼也就好寫了!

<?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」便可關注。

關注「聊聊代碼」,讓咱們一塊兒聊聊「左手代碼右手詩」的事兒。

圖片描述

相關文章
相關標籤/搜索