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

应用场景

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

结构

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

1个 interface 或者 abstract 工厂父类;
多个实现 interface 或者继承 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\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

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\FactoryMethod;

/**
* 加法
*
* Class Add
* @package Baijunyao\DesignPatterns\FactoryMethod
*/
class Add extends Operation
{
/**
* 计算结果
*
* @return int
*/
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\FactoryMethod;

/**
* 减法
*
* Class Sub
* @package Baijunyao\DesignPatterns\FactoryMethod
*/
class Sub extends Operation
{
/**
* 计算结果
*
* @return int|mixed
*/
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\FactoryMethod;

/**
* 乘法
*
* Class Mul
* @package Baijunyao\DesignPatterns\FactoryMethod
*/
class Mul extends Operation
{
/**
* 计算结果
*
* @return float|int
*/
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\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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace Baijunyao\DesignPatterns\FactoryMethod;

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

然后给加减乘数分别创建工厂并分别返回对应的产品;
AddFactory.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\FactoryMethod;

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

SubFactory.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\FactoryMethod;

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

MulFactory.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\FactoryMethod;

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

DivFactory.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\FactoryMethod;

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

使用的时候 new 各工厂即可;
运行示例;
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
<?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工厂方法模式

本文为白俊遥原创文章,转载无需和我联系,但请注明来自白俊遥博客