在标准的23种设计模式中,与工厂相关的模式有2种:工厂方法模式(Factory method pattern)和抽象工厂模式(Abstract factory pattern)。但现在很多介绍设计模式的文章又会提到一种简单工厂模式(Simple factory pattern),甚至还有静态工厂模式(Static factory pattern),那么这么多种与工厂相关的模式,它们之间是个什么关系呢?先来看图:
简单来说,简单工厂是静态工厂的升级,抽象工厂是简单工厂的升级,而不管什么工厂,它们最终都实现了工厂方法。在这里,要区分清楚的是工厂方法模式强调的是“方法”,而抽象工厂模式强调的是“工厂”,这是两个相关但又不相同的概念,就像“做饭”和“厨房”的区别,一个是谈动作,一个是谈空间。工厂方法是指的用工厂生产商品的方式来进行生产,而不管是简单工厂还是抽象工厂都是在讲对于工厂本身的管理。
没有工厂模式
举个例子来说,以前你是自己做饭吃:
$food = new Food();
静态工厂模式
自己一个人做饭吃也没什么不好,但是因为又要做饭,又要洗衣服,事情比较多,容易乱,所以不如把做饭这件事情外包出去,我就知道我们家旁边有一个小饭馆,去饭馆买饭吃,这就是一种松耦合。为了从简单入手,在这里,我们假定就是几种固定的食物,先不引入抽象商品的概念:
class StaticFactory
{
public static function orderFood(): Food
{
return new Food();
}
}
好了,至此我们有了一个静态工厂,下面就可以点餐了:
$food = StaticFactory::orderFood('chicken');
直接点餐,好简单。
简单工厂模式
但是这样想开一个连锁店,比如麦当劳这样的,怎么办呢?这时候我们就需要用到简单工厂模式:
class SimpleFactory
{
public function orderFood(): Food
{
return new Food();
}
}
和上面的方法几乎没有任何差别,唯一的差别只是少了一个static
关键词,这样我们在点餐时,就需要先新建一个工厂,然后再点餐,这就是简单工厂:
$factory = new SimpleFactory();
$food = $factory->orderFood();
抽象工厂模式
现在我们不满足于只吃麦当劳了,我们还想吃肯德基,反正它们都是连锁店,提供的服务也都差不多,这时候就用到抽象工厂模式:
abstract class AbstractFactory
{
abstract public function orderFood(): Food;
}
class MacDonald extends AbstractFactory
{
public function orderFood(): Food
{
$food = new Food();
$food->brand = 'MacDonald';
return $food;
}
}
class KFC extends AbstractFactory
{
public function orderFood(): Food
{
$food = new Food();
$food->brand = 'KFC';
return $food;
}
}
抽象工厂模式有约束了,凡是成为我工厂的,你们必须提供订餐这项基本服务。这样,我们在点餐的时候,点麦当劳就吃到了麦当劳的食物,点肯德基就吃到了肯德基的食物。
$factory1 = new MacDonald();
$food = $factory1->orderFood();
$factory2 = new KFC();
$food = $factory2->orderFood();
简单商品
我们都知道麦当劳也不只卖一种食品,可能卖鸡肉堡,也可能卖牛肉堡,既然要点餐,我们肯定要说明是点哪种汉堡,不可能他们给我们什么,我们就吃什么。你有很多种做法,我们先从最笨最简单的开始,大部分代码沿用上面的代码,只是在这里略加改动:
class MacDonald extends AbstractFactory
{
public function orderChicken(): Chicken
{
$food = new Chicken();
return $food;
}
public function orderBeef(): Beef
{
$food = new Beef();
return $food;
}
}
调用方法:
$factory = new MacDonald();
$chicken = $factory->orderChicken();
$beef = $factory->orderBeef();
换一种写法
但是这样是不是太笨了呢?我们完全可以写成一个方法:
class MacDonald extends AbstractFactory
{
public function orderFood($type)
{
if ($type == 'chicken') {
$food = new Chicken();
} elseif ($type == 'beef') {
$food = new Beef();
}
return $food;
}
}
这样我们订餐的时候,只要这样就可以了:
$factory = new MacDonald();
$chicken = $factory->orderFood('chicken');
$beef = $factory->orderFood('beef');
当然,为了应付很多种食物,你不应该写if...else
而应该写switch...case
。
抽象商品
最后,为了满足依赖反转原则(Dependency inversion principle)的要求,你实际上应该把所有的商品也抽象出来:
abstract class Food
{
public $brand;
}
class Chicken extends Food
{
}
class Beef extends Food
{
}
abstract class AbstractFactory
{
abstract public function orderFood(): Food;
}
class MacDonald extends AbstractFactory
{
public function orderFood($type): Food
{
if ($type == 'chicken') {
$food = new Chicken();
} elseif ($type == 'beef') {
$food = new Beef();
}
$food->brand = 'MacDonald',
return $food;
}
}
class KFC extends AbstractFactory
{
public function orderFood($type): Food
{
if ($type == 'chicken') {
$food = new Chicken();
} elseif ($type == 'beef') {
$food = new Beef();
}
$food->brand = 'KFC',
return $food;
}
}
$factory1 = new MacDonald();
$chicken1 = $factory1->orderFood('chicken');
$beef1 = $factory1->orderFood('beef');
$factory2 = new KFC();
$chicken2 = $factory2->orderFood('chicken');
$beef2 = $factory2->orderFood('beef');
同样还是那个鸡肉,同样还是那个牛肉,但是我们吃到了不同厂家的不同的食物。这就是抽象工厂+抽象商品的作用,最终你达到了完全解耦的目的。
工厂方法模式
说了这么半天,工厂方法模式在哪里?工厂方法模式其实已经完全溶化在每一个工厂当中,即使是最简单的静态工厂,只此一句话,就已经说明它在用工厂模式了:
return new Food();
简单来说就是:自己不去做,交给工厂去做,这就是工厂方法模式。
我这里讲的只是一个入门,希望初学者不要上来就被那些高大上的名词砸晕,吓的不敢问津了。其实设计模式没那么复杂,没什么高大上的,只要理解了它们的本质,谁都可以轻松掌握,人人可以成为架构师。当然,更高深的理解还需要你去仔细钻研,也欢迎大家提出不同见解,共同学习,共同提高。在这里,我推荐一下这个链接,在这里你可以更加详细地了解其他模式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。