一个创建点还是一族创建点
工厂方法解决「创建一个产品」的问题:把选择的决策收进一个创建点,让调用方依赖接口而不是具体类。抽象工厂解决「创建一族相互配套的产品」:选定某个主题后,必须同时使用该主题下的整组产品。当配套约束出现,就该把多个创建点收进同一个工厂接口。
基本信息
| 单产品 | 工厂方法或静态工厂,只有一个创建点 |
|---|---|
| 产品族 | 抽象工厂,一组必须配套的创建点 |
| 升级信号 | 配套约束:选了甲主题就必须同时使用甲的附件 |
| 代价 | 产品种类增加时,所有工厂实现都要同步修改 |
典型使用场景
- 界面主题:同一套皮肤的按钮、输入框、图标必须配套,避免混搭
- 跨平台适配:不同操作系统的控件族整体切换
- 数据库方言:连接、命令、参数处理与分页语法成套切换
- 测试替身:用整套桩对象替换生产实现,保证内部一致
- 云服务封装:对象存储、消息队列、密钥管理成套切换供应商
两种工厂的形态
两种工厂的形态
# 工厂方法:一个创建点,调用方依赖接口
class LoggerFactory:
def create(self) -> Logger: ...
# 抽象工厂:一族配套产品,选主题即选全套
class UiFactory: # 抽象工厂接口
def button(self) -> Button: ...
def checkbox(self) -> Checkbox: ...
def icon(self) -> Icon: ...
class DarkUiFactory(UiFactory): ... # 深色主题全套实现
class LightUiFactory(UiFactory): ... # 浅色主题全套实现什么时候该再升一层
| 判断问题 | 用工厂方法 | 用抽象工厂 |
|---|---|---|
| 产品之间是否需要配套约束 | 不需要,各自独立创建 | 需要,选主题即选全套 |
| 产品种类数量 | 单一或很少,长期稳定 | 成族出现,多个维度 |
| 新增产品的影响面 | 改一个创建点即可 | 所有工厂实现都要改 |
抽象工厂的接口一旦定死,扩产品种类的成本很高:所有实现类都要加方法。可以用接口默认方法给新方法一个临时默认实现避免全量改动,但更稳妥的做法是按能力拆小接口或分组。
静态工厂只是一个返回实例的静态方法,不涉及多态扩展。它常被当作工厂方法使用,在需要按配置切换实现时会形成长串条件分支,此时再引入多态工厂,收益才明确。