V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
ericliu001
V2EX  ›  分享创造

设计模式系列·抽象工厂模式

  •  2
     
  •   ericliu001 · 2017-05-02 07:09:57 +08:00 · 2486 次点击
    这是一个创建于 2551 天前的主题,其中的信息可能已经有所发展或是发生改变。

    午后闲谈

    公司最近项目不忙,午间小憩之后,小二找到 C 哥攀谈了起来。

    "C 哥,忙啥呢?" "也没忙啥,就是随便看看。"

    "哦哦,我最近也不怎么忙。你上次给我讲的工厂模式,受益匪浅啊!" "哈哈,是嘛!其实你不知道,还有抽象工厂模式呢!"

    "抽象工厂模式?愿闻其详。" "好,反正最近也不忙,就给你讲讲吧。"

    从奥迪车说起

    "小二,你知道,奥迪 A4 与 A6,他们使用的轮胎与灯泡是不一样的。" "是,型号不一样,轮胎与灯泡肯定不一样。"

    "假设现在需要制造 A4 与 A6 的轮胎和灯泡,你会怎么写代码?" "这个嘛,好写!"

    小二熟练的打开电脑,挥斥方遒,迅速的写出了代码。

    <?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 哥。"

    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 」即可关注。

    关注「聊聊代码」,让我们一起聊聊“左手代码右手诗”的事儿。

    14 条回复    2017-05-02 21:23:01 +08:00
    torbrowserbridge
        1
    torbrowserbridge  
       2017-05-02 08:58:46 +08:00
    那么久才来第二篇
    xiubin
        2
    xiubin  
       2017-05-02 09:19:47 +08:00
    不错不错
    nevin47
        3
    nevin47  
       2017-05-02 09:52:55 +08:00 via Android
    转给妹子看了,感觉比我自己讲的靠谱多了
    Govda
        4
    Govda  
       2017-05-02 10:26:47 +08:00
    用 PHP 讲设计模式简直一股清流... 先关注了。
    ericliu001
        5
    ericliu001  
    OP
       2017-05-02 10:30:12 +08:00
    @torbrowserbridge 哈哈,确实有点慢。公众号有全系列的文章,设计模式系列目前是 9 篇,还在持续更新中...欢迎关注啊
    ericliu001
        6
    ericliu001  
    OP
       2017-05-02 10:30:43 +08:00
    @Govda 对 php 情有独钟,哈哈
    ericliu001
        7
    ericliu001  
    OP
       2017-05-02 10:31:01 +08:00
    @nevin47 O(∩_∩)O 哈哈~
    ericliu001
        8
    ericliu001  
    OP
       2017-05-02 10:31:17 +08:00
    @xiubin 多谢关注
    qfdk
        9
    qfdk  
       2017-05-02 14:10:26 +08:00 via iPhone
    看到设计模式就进来了 给最好的语言点个赞
    johnyu
        10
    johnyu  
       2017-05-02 14:16:41 +08:00 via iPhone
    就是,怀着满满的自信和爱来高效率的做能让更多人高效率的事,对不。
    ericliu001
        11
    ericliu001  
    OP
       2017-05-02 18:26:50 +08:00
    @qfdk 哈哈,都是最好的语言
    ericliu001
        12
    ericliu001  
    OP
       2017-05-02 18:27:03 +08:00
    @johnyu yes
    no13bus
        13
    no13bus  
       2017-05-02 20:50:06 +08:00
    加油!!赞
    ericliu001
        14
    ericliu001  
    OP
       2017-05-02 21:23:01 +08:00 via iPhone
    @no13bus 终于见到了传说中的大侠
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5252 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 09:30 · PVG 17:30 · LAX 02:30 · JFK 05:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.