
简介
工厂模式,顾名思义,就是制造对象的工厂
。在学习之前,是存在很大的误解的,之前认识的工厂是简单工厂,它并不属于工厂模式的范畴,真正的工厂模式有两种,分别是工厂方法模式
、抽象工厂模式
。
工厂方法模式是使用抽象方法,使用子类继承的方式去实现。抽象工厂模式是抽象出一个工厂的接口,用具体的工厂去实现接口,然后采用组合的方式,去解藕。总而言之,两者使用的场景不一样,感觉差别挺大。
静态工厂
本章案例是制造Pizza,讲解的思路是:一个店面给顾客制造不同口味的披萨,发现效益不错,别的地方的商店想加盟,希望也能套用你的模板,再到不同地方的商店希望在本地有对应原料加工工厂。可见,随着业务的扩张,带来的变化变化也越来越多,这个时候各个模式就在应对这种变化中产生了静态工厂
、工厂方法
、抽象工厂
首先是静态工厂,在使用静态工厂前,顾客下订单的实现应该是这样的:
1 | public class PizzaStore { |
在上面代码中,我们发现ifelse代码是经常发生改变的,每增删一种口味的Pizza就要修改这段代码,这必将造成系统难以维护。在策略模式
中学到了应该将变化的部分和不变的部分分离出来,那么我们对这部分代码做一个封装,这就是简单工厂了,单独负责Pizza的创建。
实现的代码如下:
1 | public class SimplePizzaFactory { |
当新增新口味的Pizza时,我们只需修改这里的代码,create方法可以声明为静态的,当调用的时候可以不需要创建对象,直接调用。但这种设计不容易扩展,运行的时候不能修改create的行为。
那么,当有不同的加盟商到来时,这个时候create方法不得不变,要怎么办呢?这个时候我们可以这样做:

但是,更大的变化再等着我们,有些加盟商说,想要自己的一套bake、cut、box的方式。
工厂方法
工厂方法要求不同的厂商提供自己的create方法,同时可以提供自己一套烘烤、切片、包装的方式。这个时候,工厂方法来解救我们。
简单工厂将create方法进行了抽象,交给子类去实现。当定义的Pizza有自己的烘烤、切片、包装方式时,在子类定义的时候需要进行覆盖。
实现为:
1 | public abstract class PizzaStore { |
加盟商只需实现该方法,当该加盟商新增一种口味时,只需在以下实现中做一下修改,相比于简单工厂的方式,更加易于维护,而且对系统的影响度更低。
1 | public class NYStylePizzaStore extends PizzaStore { |
讲到这里,是不是对工厂方法有了大概的了解,我们来看看到底什么是工厂方法吧!

工厂方法模式
书上定义为:
定义了一个创建对象的接口,但由于子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到了子类。

到这里,可以回顾一下,如果使用简单工厂去实现,会是什么样的?会出现一个高度依赖的工厂类,当新增或删减时,对系统的影响是很大的。这样使得PizzaStore类高度依赖所有的Pizza对象,这里违背了我们新学到的一个设计原则依赖倒置原则
:
要依赖抽象,不要依赖具体类。
这个原则说明了:不能让高层组建依赖低层组件,而且,不管高层或底层组件,两者都应该依赖于抽象
。
所谓高层
组件,是由其底层
组件定义其行为的类。在这里,PizzaStore是高层组件,因为它的行为是由Pizza定义的,PizzaStore创建所有不同的Pizza对象,准备、烘烤、切片、装盒;而Pizza本身属于底层组件。

抽象工厂
到这里,系统已经有了良好的弹性框架,而且遵循设计原则。但是,我们的设计远远没有结束,比萨店成功的关键在于新鲜、高质量的原料,要是在当地建立一个原料的工厂,还能实现更大的利润。

我们首先得定义原料工厂:
1 | public interface PizzaIngredientFactory { |
将Pizza的parepar进行抽象
1 | public abstract class Pizza { |
其实这里就有点类似于工厂方法了,交给子类去实现
1 | public class CheesePizza extends Pizza { |
最后定义具体的PizzaStore
1 | public class NYPizzaStore extends PizzaStore { |
最后测试一下:
1 | PizzaStore pizzaStore = new NYPizzaStore(); |
可以跟踪一下代码执行
先是创建一个NYPizzaStore实例:
PizzaStore pizzaStore = new NYPizzaStore();
有了Pizza店了,接受订单:
pizzaStore.orderPizza("cheese");
orderPizza会先调用creatPizza方法:
Pizza pizza = creatPizza(type);
creatPizza方法调用时,涉及到原料工厂了:
pizza = new CheesePizza(ingredientFactory);
拿到Pizza后,会调用prepare方法:
1
2
3
4
5
6void preprae() {
System.out.println("Preparing " + name);
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
}最后,得到准备好的Pizza,orderPizza就会接着烘烤、切片、装盒。
抽象工厂模式
在书上定义为:
提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。
模型如图所示:
