本来这篇文章早就写完了;

最先准备用 IOS 和 Android 举例;
但是后来考虑到工厂方法和抽象工厂模式;
又用小米和华为重写了一遍;
这样可以方便的扩充低配版的红米和荣耀;
但还是觉得讲的不清楚;
最后采用了程杰老师《大话设计模式》书中的加减乘除举例;
把 C# 的代码转化并加上自己的理解写成 PHP 代码;
在此感谢程杰老师;
反复写了3种示例终于把这篇文章定稿了;
简单工厂并不属于23种设计模式;
它的实现和它的名字气质很符;
就是简单;
但是它使用的比较多;
当面对产品经理那句让人肝儿颤的”此处不要写死以后可能会改”的时候;
以及”以后可能要增加**功能”的时候;
那我们都可以先构思下是否适合简单工厂模式;
先来说说应用场景;
应用场景
在不确定有多少种操作的时候;
比如说运算符号 + - * / ;
结构
1个工厂;
1个 interface 或者 abstract 产品父类;
多个实现 interface 或者继承 abstract 的具体产品类;
示例
写一个计算器;
我们先用直观的但是并不优雅的方式来实现;
Bad.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
class Bad {
public function getResult($numberA, $operate, $numberB) { switch ($operate) { case '+': $result = $numberA + $numberB; break; case '-': $result = $numberA - $numberB; break; case '*': $result = $numberA * $numberB; break; case '/': if ($numberB != 0) { $result = $numberA / $numberB; } else { throw new \InvalidArgumentException('除数不能为0'); } break; default: throw new \InvalidArgumentException('暂不支持的运算'); } return $result; } }
|
这个类很简单就是传2个值和一个运算符号计算结果;
1 2 3
| $program = new Bad(); $result = $program->getResult(1, '+', 2); echo $result;
|
但是这种方式很不OOP;
把逻辑判断流程和实现代码各种混杂在一起不利于扩展;
就比如说除法的 case 里面的判断;
这时候我们可以把各种运算独立封装;
先建立一个 abstract ;
Operation.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
abstract class Operation {
protected $numberA = 0;
protected $numberB = 0;
abstract public function getResult();
public function setNumberA($number) { $this->numberA = $number; }
public function setNumberB($number) { $this->numberB = $number; }
}
|
然后是四则运算;
Add.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
class Add extends Operation {
public function getResult() { return $this->numberA + $this->numberB; } }
|
Sub.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
class Sub extends Operation {
public function getResult() { return $this->numberA - $this->numberB; } }
|
Mul.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
class Mul extends Operation {
public function getResult() { return $this->numberA * $this->numberB; } }
|
Div.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
class Div extends Operation {
public function getResult() { if ($this->numberB == 0) { throw new \InvalidArgumentException('除数不能为0'); } return $this->numberA / $this->numberB; } }
|
这时候我们就可以使用单独的类计算了;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $operation = new Add(); $operation->setNumberA(1); $operation->setNumberB(2); $result = $operation->getResult(); echo $result;
echo '<br>';
$operation = new Add(); $operation->setNumberA(3); $operation->setNumberB(4); $result = $operation->getResult(); echo $result;
|
当我们在代码中大量的 new 了加减乘除;
如果说我们需要要把 Add 改成 Addition ;
或者说 new 的时候需要传个参数;
这就坑爹了;
全场改起来想想都心累;
于是被这种场景坑惨了的前辈们就总结出了简单工厂模式;
张大眼睛有请我们的主角 Factory 上场;
Factory.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
class Factory {
public function create($operate) { switch ($operate) { case '+': $result = new Add(); break; case '-': $result = new Sub(); break; case '*': $result = new Mul(); break; case '/': $result = new Div(); break; default: throw new \InvalidArgumentException('暂不支持的运算'); } return $result; } }
|
当我们把这都拆开了来看的时候;
就会发现简单这个名字真是没白起;
它就是把 Bad.php 中的 case 换成具体的类;
1 2 3 4 5 6
| $factory = new Factory(); $operation = $factory->create('+'); $operation->setNumberA(1); $operation->setNumberB(2); $result = $operation->getResult(); echo $result;
|
因为我们全场都是 new 的 Factory ;
并没有 new 具体的 Add 类;
当我们面临把 Add 改成 Addition 的时候;
我们只需要在 Factory 中改一处 new Add() 就行了;
运行示例
index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| <?php
namespace Baijunyao\DesignPatterns\SimpleFactory;
require __DIR__.'/../vendor/autoload.php';
class Client {
public function bad() { $program = new Bad(); $result = $program->getResult(1, '+', 2); echo $result; }
public function bad2() { $operation = new Add(); $operation->setNumberA(1); $operation->setNumberB(2); $result = $operation->getResult(); echo $result;
echo '<br>';
$operation = new Add(); $operation->setNumberA(3); $operation->setNumberB(4); $result = $operation->getResult(); echo $result; }
public function good() { $factory = new Factory(); $operation = $factory->create('+'); $operation->setNumberA(1); $operation->setNumberB(2); $result = $operation->getResult(); echo $result; } }
$client = new Client(); $client->bad(); echo '<br>'; $client->bad2(); echo '<br>'; $client->good();
|
看似是很美好了;
然鹅;
如果我们要再增加新的运算;
那就需要改 Factory 增加 case ;
遇到可能性多的场景那 case 想想都可怕;
这就违反了开放封闭原则;
开放封闭原则简单来说就是对扩展开放对修改封闭;
理想情况下我们是不应该再改动 Factory 类的;
增加新运算应该使用扩展的方式;
这就是简单工厂的弊端了;
为此我们就需要了解下篇文章的工厂方法模式了;
github示例:https://github.com/baijunyao/design-patterns/tree/master/SimpleFactory
本文为白俊遥原创文章,转载无需和我联系,但请注明来自白俊遥博客