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

简单工厂模式

工厂(Creator)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
抽象产品(Product)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品 (Concrete Product) 角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

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
<?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{
public function getPNG(){
return new PNG();
}
public function getGIF(){
return new GIF();
}
}

$image = new Factory();
echo $image->getPNG()->getWidth();
echo '<br />';
echo $image->getGIF()->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
<?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 getImage($image){
switch($image){
case self::PNG:
return new PNG();
break;
case self::GIF:
return new GIF();
break;
}
}
}

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

echo '<br />';

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

demo4.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
<?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 getImage($path){
$file = pathinfo($path);
switch($file['extension']){
case self::PNG:
return new PNG();
break;
case self::GIF:
return new GIF();
break;
}
}
}

$image = Factory::getImage('123.png');
echo $image->getWidth();

echo '<br />';

$image = Factory::getImage('456.gif');
echo $image->getHeight();

优点
工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具 体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面中摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。
缺点
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;
使用场景
工厂类负责创建的对象比较少;
客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;
由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。