「简单工厂/工厂方法/抽象工厂」模式

场景引入

我们有一个 Pizza 店,会根据顾客的要求制作不同类型的 Pizza。目前有三种不同类型的 Pizza:「Cheese & Greek & Pepperoni」Pizza

制作每种类型的 Pizza 时,都会经历 4 个步骤:前期准备「Prepare」、烘焙「Bake」、切「Cut」、装盒「Box」

未使用设计模式的版本

下面先给出对应的类图:

1

接着给出代码:

问题:当后续需要添加新的 Pizza 类型或者删去已有的 Pizza 类型,这时就需要修改已有代码的逻辑,违背了「开闭原则」

开闭原则:开放拓展,关闭修改!!

简单工厂模式

这里还有一个原则,把变化的部分抽离出来,使变化的部分独立客户端的使用

在这个例子里面,变化的部分就是每次需要根据不同类型制作不同的 Pizza,而不变的部分就是制作完 Pizza 后的四个步骤「准备、烘焙、切、装盒」

所以我们可以把「制作不同类型 Pizza」的部分抽离出来,放到工厂中,每次需要制作 Pizza 时,去工厂里取即可!

下面先给出对应的类图:

2

接着给出核心代码:

这样当需要添加新的 Pizza 类型或者删去已有的 Pizza 类型,只用在createPizza()中 修改即可!!

可能有人会提问:这不就是把orderPizza()中的判断逻辑移到了createPizza()中吗??这样不就只是把问题移到了另一个对象中吗??

确实只是把判断逻辑移到了createPizza()中,这样关闭了对orderPizza()的修改

在现实中不仅仅只有orderPizza()需要根据类型生成 Pizza,在PizzaShopClass中也需要这样的功能,PizzaShopClass也可以直接从工厂中获取 Pizza,而不需要在自己内部实现逻辑判断

如果不引入「简单工厂模式」,对于一个改变,可能会修改多处的代码,例如:orderPizza()的逻辑判断部分、PizzaShopClass中的逻辑判断部分等等

而引入「简单工厂模式」后,对于一个改变,只需要修改工厂中对应的逻辑判读部分即可!!

工厂方法模式

现在,我们在不同地区开了分店,为了迎合当地人的习惯,同一款在不同地区的口味也应该有所区别;也需要对『前期准备「Prepare」、烘焙「Bake」、切「Cut」、装盒「Box」』四个步骤进行有针对性的改进,即对于不同地区,相同的步骤需要改变

下面先给出对应的类图:

3

接着给出代码:

由此可以引出抽象方法模式的定义:

The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

解释:工厂方法模式定义了一个创建对象的接口 (在该例子中为抽象类Pizza),让子类决定实例化哪个类 (在该例子中为NYStylePizzaStore)。工厂方法让类的实例化延迟到了子类中

为了严谨,这里再给出「工厂方法模式」的通用类图:

4

依赖倒置

Depend upon abstractions. Do not depend upon concrete classes.

解释:依赖抽象,不要依赖具体的类

当我们未使用任何设计模式时,PizzaStore直接依赖具体的实现类,其依赖关系如下图所示:

5

当我们使用了「工厂方法模式」时,PizzaStore依赖抽象类Pizza;同时具体的 Pizza 也依赖抽象类Pizza,其依赖关系如下图所示:

6

我们的设计尽可能的遵循「依赖倒置」原则,这样可以使系统实现低耦合!!

抽象工厂模式

先看工厂方法模式中的NYStyleCheesePizza类,dough、sauce、toppings等配料都是经销商自己制作,为了节约成本,存在偷工减料的情况,严重影响品牌口碑

为了杜绝这种情况,需要把不同地区不同类型 Pizza 的配料掌握在总部手中,即由总部分发配料到经销商手中,这样可以实现配料统一

下面先给出对应的类图:

7

接着给出核心代码:

为了严谨,这里再给出「工厂方法模式」的通用类图:

8

由此可以引出抽象方法模式的定义:

The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.

解释:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

工厂方法模式 vs 抽象工厂模式

下面来梳理一下这两个模式的区别!!

核心不同点:「工厂方法模式」使用类创建对象;而「抽象工厂模式」使用对象创建对象

工厂方法模式通过继承的方式创建不同类型的对象。子类考虑具体的类型 (把类的实例化延迟到了子类中),而客户端只需要知道抽象的类型即可。且对于每一个子类,只能创建一种类型的对象,详情可见NYStylePizzaStore;而抽象工厂模式通过组合的方式创建一系列的对象

用大白话再解释一波:

工厂方法模式侧重点在「方法」,定义一个抽象方法返回一个抽象类型「protected abstract Pizza createPizza(String type);」,让子类去实现这个抽象方法,确定返回具体的对象类型,所以一个方法,只能创建一个对象

抽象工厂模式侧重点在「抽象工厂」,定义了一个工厂的接口,接口中有多个创建对象的方法,所以一个工厂,可以创建一系列的对象

抽象工厂的接口是由多个工厂方法组成!!