定义
提供一个创建对象实例的功能,而无须关心其具体实现。被创建示例的类型可以是接口、抽象类,也可以是具体类。
结构和说明
示例代码
public class SimpleFactory {
public static interface Api {
void operation(String s);
}
public static class ImplA implements Api {
@Override
public void operation(String s) {
System.out.println("ImplA: " + s);
}
}
public static class ImplB implements Api {
@Override
public void operation(String s) {
System.out.println("ImplB: " + s);
}
}
public static class Factory {
public static Api createApi(int condition) {
if (1 == condition) {
return new ImplA();
} else if (2 == condition) {
return new ImplB();
} else {
return null;
}
}
}
public static class Client {
public static void main(String[] args) {
Api api = Factory.createApi(1);
api.operation("hello, world");
}
}
}
调用顺序
命名建议
- 类名称建议为 “模块名+Factory”。比如,用户模块的工厂就成为 UserFactory。
- 方法名称通常为 “get+接口名称” 或者是 “create+接口名称”。比如,有一个接口名称为 UserEbi, 那么方法名称通常为 getUserEbi 或者 createEbi。
写法
无外乎就是: 实现了一个选择一个合适的实现类来使用。
实现的功能是”选择合适的实现类” 来创建实例对象。既然要实现选择,那么就需要选择的条件或者选择的参数, 选择条件或者参数的来源通常又有以下几种。
- 来源于客户端,由 Client 传入
- 来源于配置文件,从配置文件获取用于判断的值
- 来源于程序运行期的某个值,比如从缓存中获取某个运行期的值。
优缺点
优点
- 帮助封装
简单工厂虽然简单,但是非常友好的帮助我们实现了组件的封装,然后让组件外部能够真正面向接口编程。
- 解耦
通过简单工厂,实现了客户端和具体实现类的接耦。
如同上面的例子, 客户端根本不知道具体是由谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它需要的接口对象。
缺点
- 可能增加客户端的复杂度
如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能够理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选择可配置的方式来实现。
- 不方便扩展子工厂
私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂的子类来改变创建接口的方法的行为了。不过, 通常情况下是是不需要为简单工厂创建子类的。
思考
本质
选择实现
何时选用
- 如果想要完全封装隔离具体实现,让外部只能通过接口来操作封装体,那么可以选用简单工厂,让客户端通过工厂来获取相应的接口,而无须关系具体的实现。
- 如果想要把对外创建对象的职责集中管理和控制,可以选用简单工厂,一个简单工厂可以创建很多的、不相关的对象,可以把对外创建对象的职责集中到一个简单工厂来,从而实现集中管理和控制。
相关模式
- 简单工厂和抽象工厂模式
简单工厂是用来选择实现的,可以选择任意接口的实现。一个简单工厂可以有多个选择并创建对象的方法,多个方法创建的对象可以有关系可以没有关系。
抽象工厂模式是用来选择产品簇的实现的,也就是说一般抽象工厂中有多个用于选择并创建对象的方法,但是这些方法所创建的对象之间通常是有关系的,这些被创建的对象通常是构成一个产品簇所需要的部件对象。
- 简单工厂和工厂方法模式
简单工厂和工厂方法模式也是非常类似的。
工厂方法的本质也是用来选择实现的,跟简单工厂的区别在于工厂方法是把选择的具体实现的功能延迟到子类去实现。
如果把工厂方法中选择的实现放到父类直接实现,那就等同于简单工厂。
- 简单工厂和能创建对象实例的模式
简单工厂的本质是选择实现,所以它能够跟其他任何能够具体创建对象实例的模式配合使用,比如: 单例模式、原型模式、生成器模式等。