张京
  • 10608

与工厂相关的设计模式之间的关系

 阅读约 10 分钟

在标准的23种设计模式中,与工厂相关的模式有2种:工厂方法模式(Factory method pattern)抽象工厂模式(Abstract factory pattern)。但现在很多介绍设计模式的文章又会提到一种简单工厂模式(Simple factory pattern),甚至还有静态工厂模式(Static factory pattern),那么这么多种与工厂相关的模式,它们之间是个什么关系呢?先来看图:

clipboard.png

简单来说,简单工厂是静态工厂的升级,抽象工厂是简单工厂的升级,而不管什么工厂,它们最终都实现了工厂方法。在这里,要区分清楚的是工厂方法模式强调的是“方法”,而抽象工厂模式强调的是“工厂”,这是两个相关但又不相同的概念,就像“做饭”和“厨房”的区别,一个是谈动作,一个是谈空间。工厂方法是指的用工厂生产商品的方式来进行生产,而不管是简单工厂还是抽象工厂都是在讲对于工厂本身的管理。

没有工厂模式

举个例子来说,以前你是自己做饭吃:

$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();

简单来说就是:自己不去做,交给工厂去做,这就是工厂方法模式

我这里讲的只是一个入门,希望初学者不要上来就被那些高大上的名词砸晕,吓的不敢问津了。其实设计模式没那么复杂,没什么高大上的,只要理解了它们的本质,谁都可以轻松掌握,人人可以成为架构师。当然,更高深的理解还需要你去仔细钻研,也欢迎大家提出不同见解,共同学习,共同提高。在这里,我推荐一下这个链接,在这里你可以更加详细地了解其他模式。

阅读 846发布于 2017-07-24
推荐阅读
日新亭
用户专栏

苟日新,日日新,又日新。

2820 人关注
64 篇文章
专栏主页
目录