在 GoF 的《设计模式》一书中,工厂模式被分为了三种:简单工厂、工厂方法和抽象工厂。(不过,在书中作者将简单工厂模式看作是工厂方法模式的一种特例。)在实际工作中,用得比较多的就是工厂方法模式和抽象工厂模式这两类。本篇文章,我们就先看一下抽象工场模式。
学习抽象工厂模式真正的重点和难点在于:如何找到正确的抽象。虽然抽象工厂模式很容易实现,但更重要的是我们要能意识到“正确的抽象往往都很简单也很底层”,比如,数据库的增删改查操作,日志的 debug、info、warn、error 级别,JVM 内存模型,等等。其实,抽象工厂模式想要告诉我们的不只是在写代码时随便建个抽象类就够了,而是当我们自己在对一类功能进行抽象分析时有没有找到足够简单而又通用的正确抽象。
一、模式原理分析
抽象工厂模式的原始定义是:提供了一个用于创建相关或相关对象族的接口,而无须指定其具体类。
实际上,这句话是给使用者说的。因为从使用者的角度来看,他有时可能只关心某一个抽象的大类,就好比你去租车时,你对店员说,你想要租一辆小型轿车,但具体品牌和型号你并不在意。而站在创建者的角度看,他需要关注的是如何找到这个正确的抽象大类,就好比在上面的租车场景中,你需要从普通的汽车消费者变成汽车厂的厂长一样,你必须关注最后具体的型号该怎么落地。
所以说,当我们在创建抽象工厂模式时,最终还是会涉及指定具体的实现类。换句话说,定义只是说了抽象工厂模式应该要朝着分析共性规律的方向走,而具体操作时我们还得仔细分析具体实现类该怎么实现才行。
我们再来看看抽象工厂模式原始的 UML 图:
从这个 UML 图中,我们能看出抽象工厂模式中其实包含了四个关键角色。
-
抽象工厂;
-
抽象产品(通用的一类对象或接口);
-
具体工厂;
-
具体产品(继承通用对象或接口后扩展特有属性)。
为了便于更好理解,我们这里打个比方:比如说,抽象工厂生产的抽象产品是椅子、桌子、沙发一类的家具,那具体工厂可能就在生产具体的产品:椅子设计成现代简约风格或欧洲宫廷风格,使用的材质有木质或铝制,等等。本质上椅子的特性没有发生重大改变,但在外观上,不同的具体工厂生产的椅子尺寸、材质、外观各不相同。
其中最为关键的角色并不是抽象工厂本身,而是抽象产品。抽象产品的好坏才是直接决定了抽象工厂和具体工厂能否发挥最大作用的关键所在。这也是我们在前面原则模块和思维模块里多次提到的“找到正确的抽象很重要”的原因。
明白了这个道理后,再来看下面 UML 图的代码实现,会发现思路特别清晰。
public class Client {
private Chair myChair;
private Sofa mySofa;
private Table myTable;
//通过抽象工厂来生产家具
public Client(AbsractFactory af){
myChair = af.createChair();
mySofa = af.createSofa();
myTable = af.createTable();
}
}
//抽象的家具工厂
public abstract class AbsractFactory {
abstract Chair createChair();
abstract Sofa createSofa();