工厂模式分为简单工厂模式,工厂方法模式和抽象工厂模式,它们都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,目的是降低系统中代码耦合度,并且增强了系统的扩展性。本文对这三种模式进行了介绍并且分析它们之间的区别。

简单工厂模式

简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码逻辑将会非常复杂。

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
<?php
//简单工厂方法
interface People
{
public function say();
}
class Man implements People
{
public function say()
{
echo 'this is a man ';
}
}
class Women implements People
{
public function say()
{
echo 'this is a women';
}
}
class SimpleFactory
{
public static function create($name)
{
if ($name == 'man') {
return new Man();
} elseif ($name == 'women') {
return new Women();
}
}
}
//具体调用
$man = SimpleFactory::create('man');
$man->say();
$women = SimpleFactory::create('women');
$women->say();

简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。

工厂方法模式

此模式中,通过定义一个抽象的核心工厂类,并定义创建产品对象的接口,创建具体产品实例的工作延迟到其工厂子类去完成。这样做的好处是核心类只关注工厂类的接口定义,而具体的产品实例交给具体的工厂子类去创建。当系统需要新增一个产品是,无需修改现有系统代码,只需要添加一个具体产品类和其对应的工厂子类,使系统的扩展性变得很好,符合面向对象编程的开闭原则。体代码如下:

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
//工厂方法模式
interface People
{
public function say();
}
class Man implements People
{
public function say()
{
echo 'this is a man';
}
}
class Women implements People
{
public function say()
{
echo 'this is a women';
}
}
//与简单工厂模式相比。区别在于,此处将对象的创建抽象成一个接口
interface CreatePeople
{
public function create();
}
class FactoryMan implements CreatePeople
{
public function create()
{
return new Man();
}
}
class FactoryWomen implements CreatePeople
{
public function create()
{
return new Women();
}
}
class Client
{
// 具体生产对象并执行对象方法测试
public function test() {
$factory = new FactoryMan();
$man = $factory->create();
$man->say();
$factory = new FactoryWomen();
$man = $factory->create();
$man->say();
}
}
// 执行
$demo = new Client();
$demo->test();

工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

此模式是对工厂方法模式的进一步扩展。在工厂方法模式中,一个具体的工厂负责生产一类具体的产品,即一对一的关系,但是,如果需要一个具体的工厂生产多种产品对象,那么就需要用到抽象工厂模式了。

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
interface TV{
public function open();
public function watch();
}
class HaierTv implements TV
{
public function open()
{
echo "Open Haier TV <br>";
}
public function watch()
{
echo "I'm watching TV <br>";
}
}
interface PC{
public function work();
public function play();
}
class LenovoPc implements PC
{
public function work()
{
echo "I'm working on a Lenovo computer <br>";
}
public function play()
{
echo "Lenovo computers can be used to play games <br>";
}
}
abstract class Factory{
abstract public static function createPc();
abstract public static function createTv();
}
class ProductFactory extends Factory
{
public static function createTV()
{
return new HaierTv();
}
public static function createPc()
{
return new LenovoPc();
}
}
$newTv = ProductFactory::createTV();
$newTv->open();
$newTv->watch();
$newPc = ProductFactory::createPc();
$newPc->work();
$newPc->play();

在上面的Factory抽象类中,定义了两个抽象方法,这两个抽象方法分别用来生产不同的产品(即由不同类实例化的对象)。

工厂方法模式和抽象工厂模式对比

通过以上代码:我们来对比一下工厂方法模式和抽象工厂模式:

  • 工厂方法模式中

当我需要多生产一种新的产品,比如factoryKid这个产品,我需要专门再设一个factoryKid的工厂,即添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Kid implements People{
public function say()
{
echo 'this is a kid';
}
}
class FactoryKid implements CreatePeople
{
public function create()
{
return new Kid();
}
}
  • 抽象工厂模式中

同样当我需要多生产一种新的产品,比如生产一个iphone,此时我需要修改工厂父类里的接口,并且在具体工厂类ProductFactory这个工厂里增加一条createPhone生产线(即类里面的方法),所需添加的代码如下:

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
interface Phone{
public function work();
public function sms();
}
class IPhone implements Phone
{
public function work()
{
echo "I'm iphone <br>";
}
public function sms()
{
echo "this is an iphone <br>";
}
}
//在原来的抽象工厂类中添加方法声明
abstract class Factory{
abstract public static function createPc();
abstract public static function createTv();
abstract public static function createPhone();
}
//在原来的工厂类里添加一个方法
class ProductFactory extends Factory
{
public static function createTV()
{
return new HaierTv();
}
public static function createPc()
{
return new LenovoPc();
}
public static function createPhone()
{
return new IPhone();
}
}

从上面的分析可以看出,要生产一个新的产品,抽象工厂模式并不比工厂方法模式更为便捷,那么抽象工厂模式的好处在哪呢?它优点就是在于是增加固定类型产品的不同具体工厂比较方便,比如我要增加一个生产同样类型产品的具体工厂Product2Factory,那么就再建一个Product2Factory类继承Factory就可以了。

最后的最后,总结一下工厂方法模式和抽象工厂模式的核心区别
  • 工厂方法模式利用继承,抽象工厂模式利用组合
  • 工厂方法模式产生一个对象,抽象工厂模式产生一族对象
  • 工厂方法模式利用子类创造对象,抽象工厂模式利用接口的实现创造对象