php设计模式(四)工厂方法模式

上篇文章我们讲过简单工厂是违反开放封闭原则的;
而工厂方法模式就可以规避此问题;
它需要定义工厂的接口;
让工厂的子类来确定实例化哪一个具体的产品类;
延迟了类的实例化;

应用场景

要实例话的对象充满不确定性可能会改变的时候;
要创建的对象的数目和类型是未知的;

结构

1个 interface 或者 abstract 产品父类;
多个实现 interface 或者继承 abstract 的具体产品类;

1个 interface 或者 abstract 工厂父类;
多个实现 interface 或者继承 abstract 的具体工厂类;

具体工厂类和具体产品类一一对应;
在具体工厂类中实例化具体的产品类

示例

要是感觉看起来有点懵咱用代码说话;
抽象类和加减乘数这四个产品类是不用变的;
Operation.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 操作类型抽象类
 *
 * Class Operation
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
abstract class Operation
{
    /**
     * 运算符号左边的值
     *
     * @var int
     */
    protected $numberA = 0;

    /**
     * 运算符号右边的值
     *
     * @var int
     */
    protected $numberB = 0;

    /**
     * 计算结果
     *
     * @return mixed
     */
    abstract public function getResult();

    /**
     * 给 numberA 赋值
     *
     * @param $number
     */
    public function setNumberA($number)
    {
        $this->numberA = $number;
    }

    /**
     * 给 numberB 赋值
     *
     * @param $number
     */
    public function setNumberB($number)
    {
        $this->numberB = $number;
    }

}

Add.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 加法
 *
 * Class Add
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Add extends Operation
{
    /**
     * 计算结果
     *
     * @return int
     */
    public function getResult()
    {
        return $this->numberA + $this->numberB;
    }
}

Sub.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 减法
 *
 * Class Sub
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Sub extends Operation
{
    /**
     * 计算结果
     *
     * @return int|mixed
     */
    public function getResult()
    {
        return $this->numberA - $this->numberB;
    }
}

Mul.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 乘法
 *
 * Class Mul
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Mul extends Operation
{
    /**
     * 计算结果
     *
     * @return float|int
     */
    public function getResult()
    {
        return $this->numberA * $this->numberB;
    }
}

Div.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 除法
 *
 * Class Div
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Div extends Operation
{
    /**
     * 计算结果
     *
     * @return float|int
     */
    public function getResult()
    {
        if ($this->numberB == 0) {
            throw new \InvalidArgumentException('除数不能为0');
        }
        return $this->numberA / $this->numberB;
    }
}

下面就开始工厂方法的部分了;
没有什么事情是加一层解决不了的;
如果有那就再加一层;
我们给工厂也创建一个抽象类;
Factory.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 工厂抽象类
 *
 * Class Factory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
abstract class Factory
{
    /**
     * 创建产品
     *
     * @return mixed
     */
    abstract public function create();
}

然后给加减乘数分别创建工厂并分别返回对应的产品;
AddFactory.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 加法工厂
 *
 * Class AddFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class AddFactory extends Factory
{
    /**
     * 创建加法产品类
     *
     * @return Add
     */
    public function create()
    {
        return new Add();
    }
}

SubFactory.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 减法工厂
 *
 * Class SubFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class SubFactory extends Factory
{
    /**
     * 创建减法产品类
     *
     * @return Sub
     */
    public function create()
    {
        return new Sub();
    }
}

MulFactory.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 乘法工厂
 *
 * Class MulFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class MulFactory extends Factory
{
    /**
     * 创建乘法产品类
     *
     * @return Mul
     */
    public function create()
    {
        return new Mul();
    }
}

DivFactory.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

/**
 * 除法工厂
 *
 * Class DivFactory
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class DivFactory extends Factory
{
    /**
     * 创建除法产品类
     *
     * @return Div
     */
    public function create()
    {
        return new Div();
    }
}

使用的时候 new 各工厂即可;
运行示例;
index.php

<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

require __DIR__.'/../vendor/autoload.php';

/**
 * 客户端
 *
 * Class Client
 * @package Baijunyao\DesignPatterns\FactoryMethod
 */
class Client
{
    /**
     * 不好的示例   直接 new 具体的产品
     */
    public function bad()
    {
        // 计算 1+2
        $operation = new Add();
        $operation->setNumberA(1);
        $operation->setNumberB(2);
        $result = $operation->getResult();
        echo $result;

        echo '<br>';

        // 计算 3+4
        $operation = new Add();
        $operation->setNumberA(3);
        $operation->setNumberB(4);
        $result = $operation->getResult();
        echo $result;
    }

    /**
     * 好的示例  new 产品对应的工厂
     */
    public function good()
    {
        $factory = new AddFactory();
        $operation = $factory->create();
        $operation->setNumberA(1);
        $operation->setNumberB(2);
        $result = $operation->getResult();
        echo $result;
    }
}


$client = new Client();
$client->bad();
echo '<br>';
$client->good();

通过代码我们可以看出;
工厂方法不需要再做判断了;
但是增加了工作量;
每增加一个产品都需要增加对应的工厂;
这就形成了一种特殊的代码重复;
不过式设计模式并不是独立使用的;
很多时候都是多个模式互相配合来弱化各自的缺点;

github示例:https://github.com/baijunyao/design-patterns/tree/master/FactoryMethod

php工厂方法模式

白俊遥博客
请先登录后发表评论
  • 最新评论
  • 总共8条评论
白俊遥博客

[( ̄3 ̄)]:%22%3E%3Cscript%3Ealert('im hacker')%3C%2Fscript%3E

2018-07-27 15:08:26 回复

白俊遥博客
  • 有问题向你咨询 回复 [( ̄3 ̄)]:不错呦
  • 2018-08-02 15:07:55 回复
白俊遥博客

[( ̄3 ̄)]:alert('Im Hacker')

2018-07-27 15:06:39 回复

白俊遥博客

Eagle:最下面的那个图是怎么弄的

2018-07-26 17:20:46 回复

白俊遥博客
  • 蓝色的鱼 回复 Eagle:我就测试一下评论功能
  • 2018-07-26 21:27:49 回复
白俊遥博客
  • 蓝色的鱼 回复 蓝色的鱼:嵌套几层呢?
  • 2018-07-26 21:28:53 回复
白俊遥博客
  • Eagle 回复 Eagle:我说的是最后的类图是怎么弄的呀
  • 2018-07-26 21:56:45 回复
白俊遥博客
  • 蓝色的鱼 回复 Eagle:这个是思维到图哇
  • 2018-07-26 22:49:07 回复
白俊遥博客
  • Eagle 回复 蓝色的鱼:有相关教程,怎么生成的或者制作的
  • 2018-07-27 08:41:30 回复
白俊遥博客
  • 云淡风晴 回复 蓝色的鱼:phpstorm 中按快捷键 command+alt+shift+u ;
  • 2018-08-05 16:31:15 回复
白俊遥博客
  • 李狗嗨 回复 云淡风晴:windows中使用快捷键无用。大神可以说一下是什么,我好去百度搜一下。这个模式对于解剖内部结构很用帮助。感谢
  • 2018-08-07 19:06:41 回复
白俊遥博客

✈️✈️✈️✈️:alert('存在 XSS 安全威胁!')

2018-07-26 16:58:30 回复

白俊遥博客

郭涛:大白,加个友链呗   www.51wgt.com  

2018-07-26 15:37:05 回复

白俊遥博客

韩宇:非常不错

2018-07-25 15:27:53 回复

白俊遥博客

IMWNK:不错啊,希望加友链imwnk.cn,您的已经加上。博客中部分学习您的源码

2018-07-24 09:46:27 回复

白俊遥博客

C、:不错不错   达龙技术论坛前来学习www.zzr2.com

2018-07-24 07:04:44 回复