抽象工厂是什么
为一族相关产品提供创建接口:同一风格下的按钮、输入框、滚动条由同一个工厂产出,产品族内部保持一致,切换风格时只换工厂实现。它的关键在于「族」——产品之间需要搭配使用;如果只是创建单个对象,工厂方法或静态工厂就够了。代价是新增一种产品种类时,所有工厂实现都要跟着改。
基本信息
| 意图 | 一致产品族的创建接口 |
|---|---|
| 适合 | 多套外观、驱动或方言并存 |
| 代价 | 新增产品种类要改所有工厂实现 |
| 相关 | 工厂方法、静态工厂、原型(可缓存产品实例) |
典型使用场景
- 跨平台界面:同一平台下的控件必须搭配,不能混用两套风格
- 多数据库方言:同一批 DAO 实现必须属于同一种方言
- 主题与皮肤:主题切换时所有组件同时更换
- 测试替身:把整套协作者替换成内存实现,一次切换整族
- 多租户配置:不同租户使用不同实现组合,但调用方接口一致
结构示意(Java)
结构示意(Java)
interface GuiFactory {
Button button();
Checkbox checkbox();
}
class MacFactory implements GuiFactory {
@Override public Button button() { return new MacButton(); }
@Override public Checkbox checkbox() { return new MacCheckbox(); }
}
class WinFactory implements GuiFactory { /* 同上的 Windows 实现 */ }
// 调用方只持有工厂接口,切换风格只换注入的实现
class Form {
private final GuiFactory factory; // 构造注入
Form(GuiFactory factory) { this.factory = factory; }
Button submit() { return factory.button(); }
}与其它创建方式对比
| 方式 | 产出 | 适用 |
|---|---|---|
| 抽象工厂 | 一族相关产品 | 族内需要保持一致 |
| 工厂方法 | 单一产品 | 子类决定创建哪种实现 |
| 静态工厂方法 | 单一产品 | 语言层面替代构造器 |
| 依赖注入容器 | 按配置装配的整对象图 | 产品族由配置决定 |
抽象工厂常与依赖注入容器并存:容器负责选择并注入哪个工厂实现,工厂负责保证族内一致。两者职责不同,不必二选一。
产品族只有一套且短期不会有第二套时,这层抽象属于过度设计:多出的接口与实现类换不来任何灵活性,删除成本还很高。判断依据是「是否真的存在多套需要整体切换的实现」。