定义:用来实现 创建对象和对象的使用分离,将对象的创建交给专门的工厂类负责。
应用场景
在不确定有多少种操作的时候;
比如运算符号 + - * 、;
结构
1个工厂类;
1个interface或者abstract产品父类
多个实现interface或者继承abstract的具体产品类;
示例
写一个计算器;
我们先用直观的常用的方式来实现;
<?php
/**
* 不好的示例
* Class Bad
*/
class Bad
{
/**
* 计算结果
*
* @param int $numberA
* @param string $operate
* @param int $numberB
* @return int|float|int
*/
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个值和一个运算符,然后计算结果;
$program = new Bad();
$result = $program->getResult(1, '+', 2);
echo $result;
但是这种方式,很不OOP;
把逻辑判断流程和实现代码都放在一起,不利于扩展;
这个时候,我们可以这样;
先建一个abstract类;
<?php
/**
* 操作类型抽象类
*
* Class Operation
*/
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
/**
* 加法
*
* Class Add
*/
class Add extends Operation
{
/**
* 计算结果
*
* @return int
*/
public function getResult()
{
return $this->numberA + $this->numberB;
}
}
Sub.php
<?php
/**
* 减法
*
* Class Sub
*/
class Sub extends Operation
{
/**
* 计算结果
*
* @return int|mixed
*/
public function getResult()
{
return $this->numberA - $this->numberB;
}
}
Mul.php
<?php
/**
* 乘法
*
* Class Mul
*/
class Mul extends Operation
{
/**
* 计算结果
*
* @return float|int
*/
public function getResult()
{
return $this->numberA * $this->numberB;
}
}
Div.php
<?php
/**
* 除法
*
* Class Div
*/
class Div extends Operation
{
/**
* 计算结果
*
* @return float|int
*/
public function getResult()
{
if ($this->numberB == 0) {
throw new \InvalidArgumentException('除数不能为0');
}
return $this->numberA / $this->numberB;
}
}
现在就可以使用单独的类计算了;
// 计算 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 了加减乘除;
如果说我们需要要把 Add 改成 Addition ;
或者说 new 的时候需要传个参数;
这就坑爹了;
全场改起来想想都心累;
于是被这种场景坑惨了的前辈们就总结出了简单工厂模式;
张大眼睛有请我们的主角 Factory 上场;
Factory.php
<?php
/**
* 工厂类
*
* Class Factory
*/
class Factory
{
/**
* 创建一种运算
*
* @param $operate
* @return Add|Div|Mul|Sub
*/
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 换成具体的类;
$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() 就行了;
看似很美好;
however;
如果我们要再增加新的运算;
那就需要改 Factory 增加 case ;
遇到可能性多的场景那 case 想想都可怕;
这就违反了开放封闭原则;
开放封闭原则简单来说就是对扩展开放对修改封闭;
理想情况下我们是不应该再改动 Factory 类的;
增加新运算应该使用扩展的方式;
这就是简单工厂的弊端了;
为此我们就需要了解下篇文章的工厂方法模式了;