工厂方法(上)
简单工厂方法
本期要介绍的是工厂方法,什么是工厂方法呢?还是接着上次的栗子来说
这里附上上一篇文章 PHP面向对象编程的链接
回顾上一篇文章讲的内容,实现一个计算器,从面向过程到面向对象
以下是根据面向对象思想和部分设计原则改良过的代码(上期栗子4)
/**
* Class Validate 校验类
* Created by PhpStorm.
* Created Time Created Time 2019-12-22 11:20
*
* PHP version 7.1
*
* @category Validate
*/
class Validate
{
/**
* Fun checkNumber 数字校验
* Created Time 2019-12-22 11:03
*
* @param float $number1
* @param float $number2
*
* @return bool
*/
public function checkNumber(float $number1, float $number2):bool
{
if (!is_numeric($number1) || !is_numeric($number2)) {
return false;
}
return true;
}
/**
* Fun checkDivision 除法校验
* Created Time 2019-12-22 11:11
*
* @param float $number
*
* @return bool
*/
public function checkDivision(float $number):bool
{
return $number == 0 ? false : true;
}
}
/**
* Class Calculation 计算方法抽象类
* Created by PhpStorm.
* Created Time 2019-12-23 14:24
*
* PHP version 7.1
*
* @category Calculation
*/
abstract class Calculation
{
/**
* Calculation constructor.
*/
public function __construct()
{
$this->validate = new Validate();
}
/**
* Fun execute 计算方法
* Created Time 2019-12-23 14:25
* Author huqimeng <huqimeng@xiaozhu.com>
*
* @param float $number1
* @param float $number2
*
* @return mixed
*/
abstract public function execute(float $number1, float $number2);
}
/**
* Class Addition 加法类
* Created by PhpStorm.
* Created Time 2019-12-23 15:01
*
* PHP version 7.1
*
* @category Addition
*/
class Addition extends Calculation
{
/**
* Fun execute 加法
* Created Time 2019-12-23 15:07
*
* @param float $number1
* @param float $number2
*
* @return bool|float|mixed
*/
public function execute(float $number1, float $number2)
{
if ($this->validate->checkNumber($number1, $number2)) {
return $number1 + $number2;
}
return false;
}
}
/**
* Class Subtraction 减法类
* Created by PhpStorm.
* Created Time 2019-12-23 15:08
*
* PHP version 7.1
*
* @category Subtraction
*/
class Subtraction extends Calculation
{
/**
* Fun execute 减法
* Created Time 2019-12-23 15:09
*
* @param float $number1
* @param float $number2
*
* @return bool|float|mixed
*/
public function execute(float $number1, float $number2)
{
if ($this->validate->checkNumber($number1, $number2)) {
return $number1 - $number2;
}
return false;
}
}
/**
* Class Multiplication 乘法类
* Created by PhpStorm.
* Created Time 2019-12-23 15:11
*
* PHP version 7.1
*
* @category Multiplication
*/
class Multiplication extends Calculation
{
/**
* Fun execute 乘法
* Created Time 2019-12-23 15:12
*
* @param float $number1
* @param float $number2
*
* @return bool|float|int|mixed
*/
public function execute(float $number1, float $number2)
{
if ($this->validate->checkNumber($number1, $number2)) {
return $number1 * $number2;
}
return false;
}
}
/**
* Class Division 除法类
* Created by PhpStorm.
* Created Time 2019-12-23 15:15
*
* PHP version 7.1
*
* @category Division
*/
class Division extends Calculation
{
/**
* Fun execute 除法
* Created Time 2019-12-23 15:18
*
* @param float $number1
* @param float $number2
*
* @return bool|float|int|mixed
*/
public function execute(float $number1, float $number2)
{
if ($this->validate->checkDivision($number2)) {
if ($this->validate->checkNumber($number1, $number2)) {
return $number1 / $number2;
}
}
return false;
}
}
这段代码中,倘若需要进行加法运算,可以对加法类实例化
new Addition();
可以想象以下,计算器以后会有成百上千种计算方法,使用不同的计算方法就要实例化不同的计算方法对象,这是一件十分繁琐的事情。采用工厂方法就可以解决这个问题。
简单工厂方法(栗子1)
/**
* Class CalculationFactory 计算方法工厂类
* Created by PhpStorm.
* Created Time 2020-01-05 10:11
*
* PHP version 7.1
*
* @category CalculationFactory
*/
class CalculationFactory
{
/**
* Fun calculationCreator 计算方法工厂方法
* Created Time 2020-01-05 10:15
*
* @param string $symbol
*
* @return Addition|bool|Division|Multiplication|Subtraction
*/
public function calculationCreator(string $symbol)
{
switch ($symbol) {
case "addition" :
return new Addition();
case "subtraction" :
return new Subtraction();
case "multiplication" :
return new Multiplication();
case "division" :
return new Division();
default :
return false;
}
}
}
运行结果
echo "计算结果为:" . (new CalculationFactory())->calculationCreator('addition')->execute(3, 1);
计算结果为:4
工厂方法
以上(栗子1)是一个简单工厂方法的案例,通过一个计算方法工厂类,“生产”出我们需要的计算方法对象,在一定程度上方便和规范了计算方法对象的使用。
当然案例本身还存在很多问题
- 最大的问题就是该案例违反了设计原则中的开闭原则
- 建议将工厂方法类中“生产”对象的方法变成静态方法(static),客户端在使用的时候直接通过类调用,避免频繁实例化对象带来的系统额外开销
- 等等
针对上述主要的两点问题改善一下代码(栗子2)
/**
* Interface CalculationInterFaceFactory
*/
interface CalculationInterFaceFactory
{
/**
* Fun calculationCreator 计算方法对象创建者
* Created Time 2020-01-05 13:22
* Author huqimeng <huqimeng@xiaozhu.com>
*
*
* @return Calculation
*/
public static function calculationCreator():Calculation;
}
/**
* Class CalculationAbstractFactory 计算方法抽象工厂类
* Created by PhpStorm.
* Created Time 2020-01-05 13:23
*
* PHP version 7.1
*
* @category CalculationAbstractFactory
*/
abstract class CalculationAbstractFactory implements CalculationInterFaceFactory
{
/**
* CalculationAbstractFactory constructor.
*/
private function __construct(){}
/**
* @inheritdoc
*/
abstract static public function calculationCreator():Calculation;
}
/**
* Class CalculationFactory 加法工厂类
* Created by PhpStorm.
* Created Time 2020-01-05 13:29
*
* PHP version 7.1
*
* @category AdditionFactory
*/
class AdditionFactory extends CalculationAbstractFactory
{
/**
* @inheritdoc
*/
public static function calculationCreator():Calculation
{
return new Addition();
}
}
/**
* Class CalculationFactory 减法工厂类
* Created by PhpStorm.
* Created Time 2020-01-05 13:31
*
* PHP version 7.1
*
* @category SubtractionFactory
*/
class SubtractionFactory extends CalculationAbstractFactory
{
/**
* @inheritdoc
*/
public static function calculationCreator():Calculation
{
return new Subtraction();
}
}
运行结果
echo "计算结果为:" . AdditionFactory::calculationCreator()->execute(3, 1);
计算结果为:4
这里将每个计算方法的实例化变成单独的类,加法是加法工厂类,减法是减法工厂类,如需扩展只需添加新的计算方法工厂类并继承抽象计算方法工厂类即可。
这就是经典/基础/重要的设计模式之一工厂模式
- 之前的简单工厂模式并不能称之为设计模式,只是为了引入工厂模式的概念,方便理解
大家可能会有这样的疑问, “new Addition()”不好吗?多简单啊这样写,为什么非要使用工厂呢?
当代码规模很小的时候确实看不出这两者有什么区别,随着代码规模的扩大,每个计算方法会被不同的客户端多次调用。
通过解决上篇文章中的遗留问题可以得到答案。
上篇文章中提到,现在的计算方法也不完全符合单一职责原则,主要的原因就是计算方法类中的执行方法同时还承担了校验数字的职责,针对这个问题代码修改如下(栗子3)
/**
* Interface CalculationInterface
*/
interface CalculationInterface{
/**
* Fun execute 计算方法
* Created Time 2020-01-05 14:01
*
* @return float
*/
public function execute():float ;
}
/**
* Class Calculation 计算方法抽象类
* Created by PhpStorm.
* Created Time 2020-01-05 14:02
*
* PHP version 7.1
*
* @category Calculation
*/
abstract class Calculation implements CalculationInterface
{
protected $validate;
protected $number1;
protected $number2;
/**
* Calculation constructor.
* @param $number1
* @param $number2
*/
public function __construct($number1, $number2)
{
$this->validate = new Validate();
$this->number1 = $number1;
$this->number2 = $number2;
if (!$this->validate->checkNumber($this->number1, $this->number2)) {
exit('非法的数字!');
}
return true;
}
/**
* @inheritdoc
*/
abstract public function execute():float ;
}
/**
* Class Addition 加法类
* Created by PhpStorm.
* Created Time 2020-01-19 14:07
*
* PHP version 7.1
*
* @category Addition
*/
class Addition extends Calculation
{
/**
* @inheritdoc
*/
public function execute():float
{
return $this->number1 + $this->number2;
}
}
在计算方法抽象类的构造方法中对数字进行了校验,这样继承抽象类的计算方法只需要执行对应的操作即可。
对于除法,有区别其他计算方法的验证,可以重写父类的构造方法(多态)。
/**
* Class Division 除法类
* Created by PhpStorm.
* Created Time 2020-01-19 14:29
*
* PHP version 7.1
*
* @category Division
*/
class Division extends Calculation
{
/**
* Division constructor.
* @param float $number1
* @param float $number2
*/
public function __construct(float $number1, float $number2)
{
parent::__construct($number1, $number2);
if (!$this->validate->checkDivision($this->number2)) {
exit('除数不能为0!');
}
return true;
}
/**
* @inheritdoc
*/
public function execute():float
{
return $this->number1 / $this->number2;
}
}
不管是加法还是除法的改动,都可以看到,实例化计算类的方式已经发生了改变
此时,所有计算方法类的实例化方式发生了变化。那意味着,如果没有使用工厂方法,实例化所有计算方法类的位置都要发生变化,但使用工厂方法的话只用修改计算方法工厂类中的创建者方法即可。维护成本高下立判。
针对计算方法的改动修改工厂方法
/**
* Interface CalculationInterFaceFactory
*/
interface CalculationInterFaceFactory
{
/**
* Fun calculationCreator 计算方法对象创建者
* Created Time 2020-01-19 15:27
*
* @param float $number1
* @param float $number2
*
* @return CalculationInterface
*/
public static function calculationCreator(float $number1, float $number2):CalculationInterface;
}
/**
* Class CalculationAbstractFactory 计算方法抽象工厂类
* Created by PhpStorm.
* Created Time 2020-01-19 15:33
*
* PHP version 7.1
*
* @category CalculationAbstractFactory
*/
abstract class CalculationAbstractFactory implements CalculationInterFaceFactory
{
/**
* CalculationAbstractFactory constructor.
*/
private function __construct(){}
/**
* @inheritdoc
*/
abstract static public function calculationCreator(float $number1, float $number2):CalculationInterface;
}
/**
* Class AdditionFactory 加法工厂类
* Created by PhpStorm.
* Created Time 2020-01-19 15:41
*
* PHP version 7.1
*
* @category AdditionFactory
*/
class AdditionFactory extends CalculationAbstractFactory
{
/**
* @inheritdoc
*/
public static function calculationCreator(float $number1, float $number2):CalculationInterface
{
return new Addition($number1, $number2);
}
}
/**
* Class DivisionFactory 除法工厂类
* Created by PhpStorm.
* Created Time 2020-01-19 16:00
*
* PHP version 7.1
*
* @category DivisionFactory
*/
class DivisionFactory extends CalculationAbstractFactory
{
/**
* @inheritdoc
*/
public static function calculationCreator(float $number1, float $number2):CalculationInterface
{
return new Division($number1, $number2);
}
}
总结
本文中的知识点总结
工厂方法
- 工厂方法是定义一个创建产品对象的工厂接口,通过这个工厂类来“生产”所有产品的对象
简单工厂方法
- 引入工厂方法的思想,使得客户端只用关注工厂,不用关注实例化对象的细节
- 违背了开闭原则
工厂方法的优点
- 是简单工厂方法的进一步延伸,遵守了开闭原则
- 当代码规模较大时,扩展方便,维护成本低
- 当代码规模较小时,使用繁琐而且理解上有一定难度