zoukankan      html  css  js  c++  java
  • PHP 设计模式系列 —— 工厂方法模式(Factory Method)(转)

    1、模式定义

    定义一个创建对象的接口,但是让子类去实例化具体类。工厂方法模式让类的实例化延迟到子类中。

    2、问题引出

    框架需要为多个应用提供标准化的架构模型,同时也要允许独立应用定义自己的域对象并对其进行实例化。

    3、解决办法

    工厂方法以模板方法的方式创建对象来解决上述问题。父类定义所有标准通用行为,然后将创建细节放到子类中实现并输出给客户端。

    人们通常使用工厂模式作为创建对象的标准方式,但是在这些情况下不必使用工厂方法:实例化的类永远不会改变;或者实例化发生在子类可以轻易覆盖的操作中(比如初始化)。

    4、UML类图

    Factory-Method-UML

    5、示例代码

    FactoryMethod.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethod;
    
    /**
     * 工厂方法抽象类
     */
    abstract class FactoryMethod
    {
    
        const CHEAP = 1;
        const FAST = 2;
    
        /**
         * 子类必须实现该方法
         *
         * @param string $type a generic type
         *
         * @return VehicleInterface a new vehicle
         */
        abstract protected function createVehicle($type);
    
        /**
         * 创建新的车辆
         *
         * @param int $type
         *
         * @return VehicleInterface a new vehicle
         */
        public function create($type)
        {
            $obj = $this->createVehicle($type);
            $obj->setColor("#f00");
    
            return $obj;
        }
    }

    ItalianFactory.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethod;
    
    /**
     * ItalianFactory是意大利的造车厂
     */
    class ItalianFactory extends FactoryMethod
    {
        /**
         * {@inheritdoc}
         */
        protected function createVehicle($type)
        {
            switch ($type) {
                case parent::CHEAP:
                    return new Bicycle();
                    break;
                case parent::FAST:
                    return new Ferrari();
                    break;
                default:
                    throw new InvalidArgumentException("$type is not a valid vehicle");
            }
        }
    }

    GermanFactory.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethod;
    
    /**
     * GermanFactory是德国的造车厂
     */
    class GermanFactory extends FactoryMethod
    {
        /**
         * {@inheritdoc}
         */
        protected function createVehicle($type)
        {
            switch ($type) {
                case parent::CHEAP:
                    return new Bicycle();
                    break;
                case parent::FAST:
                    $obj = new Porsche();
                    //因为我们已经知道是什么对象所以可以调用具体方法
                    $obj->addTuningAMG();
    
                    return $obj;
                    break;
                default:
                    throw new InvalidArgumentException("$type is not a valid vehicle");
            }
        }
    }

    VehicleInterface.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethod;
    
    /**
     * VehicleInterface是车辆接口
     */
    interface VehicleInterface
    {
        /**
         * 设置车的颜色
         *
         * @param string $rgb
         */
        public function setColor($rgb);
    }

    Porsche.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethod;
    
    /**
     * Porsche(保时捷)
     */
    class Porsche implements VehicleInterface
    {
        /**
         * @var string
         */
        protected $color;
    
        /**
         * @param string $rgb
         */
        public function setColor($rgb)
        {
            $this->color = $rgb;
        }
    
        /**
         * 尽管只有奔驰汽车挂有AMG品牌,这里我们提供一个空方法仅作代码示例
         */
        public function addTuningAMG()
        {
        }
    }

    Bicycle.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethod;
    
    /**
     * Bicycle(自行车)
     */
    class Bicycle implements VehicleInterface
    {
        /**
         * @var string
         */
        protected $color;
    
        /**
         * 设置自行车的颜色
         *
         * @param string $rgb
         */
        public function setColor($rgb)
        {
            $this->color = $rgb;
        }
    }

    Ferrari.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethod;
    
    /**
     * Ferrari(法拉利)
     */
    class Ferrari implements VehicleInterface
    {
        /**
         * @var string
         */
        protected $color;
    
        /**
         * @param string $rgb
         */
        public function setColor($rgb)
        {
            $this->color = $rgb;
        }
    }
    

    6、测试代码

    Tests/FactoryMethodTest.php

    <?php
    
    namespace DesignPatternsCreationalFactoryMethodTests;
    
    use DesignPatternsCreationalFactoryMethodFactoryMethod;
    use DesignPatternsCreationalFactoryMethodGermanFactory;
    use DesignPatternsCreationalFactoryMethodItalianFactory;
    
    /**
     * FactoryMethodTest用于测试工厂方法模式
     */
    class FactoryMethodTest extends PHPUnit_Framework_TestCase
    {
    
        protected $type = array(
            FactoryMethod::CHEAP,
            FactoryMethod::FAST
        );
    
        public function getShop()
        {
            return array(
                array(new GermanFactory()),
                array(new ItalianFactory())
            );
        }
    
        /**
         * @dataProvider getShop
         */
        public function testCreation(FactoryMethod $shop)
        {
            // 该方法扮演客户端角色,我们不关心什么工厂,我们只知道可以可以用它来造车
            foreach ($this->type as $oneType) {
                $vehicle = $shop->create($oneType);
                $this->assertInstanceOf('DesignPatternsCreationalFactoryMethodVehicleInterface', $vehicle);
            }
        }
    
        /**
         * @dataProvider getShop
         * @expectedException InvalidArgumentException
         * @expectedExceptionMessage spaceship is not a valid vehicle
         */
        public function testUnknownType(FactoryMethod $shop)
        {
            $shop->create('spaceship');
        }
    }

    7、总结

    工厂方法模式和抽象工厂模式有点类似,但也有不同。

    工厂方法针对每一种产品提供一个工厂类,通过不同的工厂实例来创建不同的产品实例,在同一等级结构中,支持增加任意产品。

    抽象工厂是应对产品族概念的,比如说,每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。

  • 相关阅读:
    一个禁止某个document element对象选中文本的js方法
    LNMP中nginx和php的安装流程
    nginx编译
    nginx服务器管理
    nginx+phpfpm配置文件的组织结构
    win 8 x64 english key
    WdatePicker 设置时间范围在某个时间段
    Vm workstation安装win8 的问题
    android 开发中xml的解析
    多线程下载文件
  • 原文地址:https://www.cnblogs.com/shixiuxian/p/8939945.html
Copyright © 2011-2022 走看看