简单工厂
定义
在创建一个对象时不向客户暴露内部细节,并提供一个创建对象的通用接口。
简单工厂其实不是一个设计模式,反而比较像一种编程习惯。但是不要因为简单工厂不是一个“真正的”模式,就忽略了它的用法,让我们来看看它的结构图。
结构图

简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂,让简单工厂类来决定应该用哪个具体子类实例化。
这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且子类一旦发生改变,例如增加子类,那么所有的客户类都要进行修改。
实现
现在创建一个Product接口,标志实现这个接口的类为产品类。
1 | public interface Product { |
然后举例,创建三个实现Product接口的类,表示具体的产品:
1 | public class ConcreteProduct implements Product { |
1 | public class ConcreteProduct1 implements Product { |
1 | public class ConcreteProduct2 implements Product { |
然后提供SimpleFactory类,作为一个工厂,当客户端需要Product时,只需去向SimpleFactory这个工厂去获取相对应的具体实现类即可:
1 | public class SimpleFactory { |
然后下面是模拟客户类去获取Product的具体实现:
1 | public class Client { |
总结
- 简单工厂最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类去负责。
- 但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。
- 简单工厂适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。
工厂方法
定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
结构图

工厂方法模式能够封装具体类型的实例化。根据上面的类图,抽象的Creator提供了一个创建对象的方法的接口,也称为“工厂方法”。在抽象的Creator中,任何其他实现的方法,都可能使用到这个方法所制造出来的产品。但只有子类真正实现这个工厂方法并创建产品。
实现
首先Product复用上面简单工厂的代码,接下来创建一个Factory抽象类,为子类提供factoryMethod()方法,和其他看情况可重写的方法,例如anOperation()方法。
1 | public abstract class Factory { |
接着实现其三个子类,分别表示不同类型的Product的工厂:
1 | public class ConcreteFactory extends Factory { |
1 | public class ConcreteFactory1 extends Factory { |
1 | public class ConcreteFactory2 extends Factory { |
最后模拟客户端类获取不同类型的Product:
1 | public class Client { |
总结
- 工厂方法模式是简单工厂的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
- 工厂方法模式的主要优点是增加新的产品类时无须修改现有代码,并封装了产品对象的创建细节,系统具有良好的灵活性和可扩展性。
- 其缺点在于增加新产品的同时需要增加新的工厂,导致系统类的个数成对增加,在一定程度上增加了系统的复杂性。
- 工厂方法模式适用情况包括:一个类不知道它所需要的对象的类;一个类通过其子类来指定创建哪个对象;将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时无需关心是哪一个工厂子类创建产品子类,需要时再动态指定。
抽象工厂
定义
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
结构图

抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只适用于创建一个对象,这和抽象工厂模式有很大不同。
抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory中的createProductA()和createProductB()方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。
至于创建对象的家族这一概念是在Client体现,Client要通过AbstractFactory同时掉用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client需要同时创建出这两个对象。
从高层次来看,抽象工厂模式使用了组合,即Client组合了AbstractFactory,而工厂方法模式则使用了继承。
实现
首先创建抽象产品类,为具体实现类提供基础:
1 | public class AbstractProductA { |
1 | public class AbstractProductB { |
然后提供具体的实现类:
1 | public class ProductA1 extends AbstractProductA { |
1 | public class ProductA2 extends AbstractProductA { |
1 | public class ProductB1 extends AbstractProductB{ |
1 | public class ProductB2 extends AbstractProductB{ |
接下来提供抽象工厂类,为具体工厂类的实现提供基础:
1 | public abstract class AbstractFactory { |
下面实现这个具体的工厂类:
1 | public class ConcreteFactory1 extends AbstractFactory { |
1 | public class ConcreteFactory2 extends AbstractFactory { |
最后进行客户端调用即可:
1 | public class Client { |
总结
- 抽象工厂模式的主要优点是隔离了具体类的生成,使得客户并不需要知道什么被创建,而且每次可以通过具体工厂类创建一个产品族中的多个对象,增加或者替换产品族比较方便,增加新的具体工厂和产品族很方便。
- 主要缺点在于增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。
- 抽象工厂模式适用情况包括:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节;系统中有多于一个的产品族,而每次只使用其中某一产品族;属于同一个产品族的产品将在一起使用;系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
总结
- 所有的工厂都是用来封装对象的创建
- 简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户端程序从具体类解耦。
- 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象。
- 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。
- 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。
- 工厂方法允许类将实例化延迟到子类进行。
- 抽象工厂方法创建相关的对象家族,而不需要依赖他们的具体实现类。
- 依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖对象。
- 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。