PHP设计模式之工厂方法模式

工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现’开-闭 原则’(一个模块在扩展性上实现开放,而在更改性上实现闭合),实现了可扩展 。其次更复杂的层次结构,可以应用于产品复杂的场合。

以图片管理器为例

常规写法


demo1.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
<?php
header('Content-Type:text/html; charset=utf-8');

abstract class Image{
abstract public function getWidth();
abstract public function getHeight();
}

class PNG extends Image{
public function getWidth(){
return 'PNG长度为100';
}
public function getHeight(){
return 'PNG高度为200';
}
}

class GIF extends Image{
public function getWidth(){
return 'GIF长度为100';
}
public function getHeight(){
return 'GIF高度为200';
}
}

$png = new PNG();
echo $png->getWidth();

echo '<br />';

$gif = new GIF();
echo $png->getHeight();

我们会发现demo1.php调用相应的类都很麻烦,对客户端的调用提高了要求。如果只提供一种入口,我们无所谓插入任意的图片类型,那么他都会在内部创建相应的对象,那么在客户端的调用就会非常的方便。

简单工厂模式

demo2.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
<?php
header('Content-Type:text/html; charset=utf-8');

abstract class Image{
abstract public function getWidth();

abstract public function getHeight();
}

class PNG extends Image{
public function getWidth(){
return 'PNG长度为100';
}

public function getHeight(){
return 'PNG高度为200';
}
}

class GIF extends Image{
public function getWidth(){
return 'GIF长度为100';
}

public function getHeight(){
return 'GIF高度为200';
}
}

class Factory{
const PNG = 'png';
const GIF = 'gif';

static public function getMessage($image){
switch($image){
case self::PNG:
return '您将要处理PNG,是否处理呢?';
break;
case self::GIF:
return '您将要处理GIF,是否处理呢?';
break;
}
}

static public function getImage($image){
switch($image){
case self::PNG:
return new PNG();
break;
case self::GIF:
return new GIF();
break;
}
}
}

echo Factory::getMessage(Factory::PNG);
$image = Factory::getImage(Factory::PNG);
echo $image->getWidth();

echo '<br />';

echo Factory::getMessage(Factory::GIF);
$image = Factory::getImage(Factory::GIF);
echo $image->getHeight();

简单静态方法工厂已经无法满足我们扩展和需求的变动,而且工厂类包含的太多的信息,也违反了高内聚,低耦合的原则。所以,我们决定采用工厂方法模式。

工厂方法模式

使用工厂方法模式解耦、并提升内聚

demo3.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
<?php
header('Content-Type:text/html; charset=utf-8');

abstract class Image{
abstract public function getWidth();

abstract public function getHeight();
}

class PNG extends Image{
public function getWidth(){
return 'PNG长度为100';
}

public function getHeight(){
return 'PNG高度为200';
}
}

class GIF extends Image{
public function getWidth(){
return 'GIF长度为100';
}

public function getHeight(){
return 'GIF高度为200';
}
}

abstract class Factory{
abstract public function getMessage();
abstract public function getImage();
}

class Factory_PNG extends Factory{
public function getMessage(){
return '您将要处理PNG,是否要处理呢?';
}
public function getImage(){
return new PNG();
}
}

class Factory_GIF extends Factory{
public function getMessage(){
return '您将要处理GIF,是否处理呢?';
}
public function getImage(){
return new GIF();
}
}


$png = new Factory_PNG();
echo $png->getMessage();
echo $png->getImage()->getWidth();

echo '<br />';

$gif = new Factory_GIF();
echo $gif->getMessage();
echo $gif->getImage()->getHeight();

把工厂类设置成抽象规范,让每个子类工厂去负责每个类对象的生成,这样提高了灵活性,提高了内聚,降低了耦合,但丢失了客户端的便捷,也增大了维护成本。