1.2 抽象工厂模式
如果说工厂方法解决的是“创建一个产品”,那么抽象工厂(Abstract Factory)解决的是“创建一整族互相搭配的产品”。
经典例子是跨平台 UI:在 Windows 上,按钮、滚动条、菜单要有 Windows 的外观和手感;在 macOS 上则要有 macOS 的一套。你绝不希望出现“Windows 的按钮配上 macOS 的滚动条”这种风格错配。抽象工厂的核心保证就是:同一个工厂产出的所有产品,一定属于同一族。
下面的主题套件工厂里,切换主题就等于换一整套互相协调的控件——按钮、复选框、卡片同时换肤。
正在加载交互实验...
结构:工厂的工厂
抽象工厂在工厂方法之上再抽象一层:
java
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
class LightFactory implements GUIFactory {
public Button createButton() { return new LightButton(); }
public Checkbox createCheckbox() { return new LightCheckbox(); }
}
class DarkFactory implements GUIFactory {
public Button createButton() { return new DarkButton(); }
public Checkbox createCheckbox() { return new DarkCheckbox(); }
}客户端拿到的是 GUIFactory 接口,它调用 createButton()、createCheckbox(),却完全不知道自己在用 Light 还是 Dark。要整体换肤,只需在最外层换一个工厂实例。
正在加载概念检查...
一致性是它真正的卖点
很多人第一次看抽象工厂会觉得“这不就是几个工厂方法打了个包吗”。它的价值不在于代码量,而在于约束:当所有产品都从同一个工厂取出时,你在编译期就杜绝了跨族混搭。
下面的一致性检查器让你手动给每个控件挑来源。一旦你混入了不同操作系统的实现,它会立刻报警;而“用某个工厂对齐”按钮则演示了抽象工厂如何从源头消除这种错误。
正在加载交互实验...
代价:新增产品种类很贵
抽象工厂有一个著名的弱点:增加一个新的产品种类(比如除了按钮、复选框,现在还要 Slider)非常痛苦,因为你必须修改 GUIFactory 接口以及它的每一个实现工厂。
所以它的适用前提是:
- 产品的“种类”相对稳定(按钮、复选框这些不常变);
- 但产品的“族”会经常增加(今天 Light/Dark,明天还要 Cyber、高对比度无障碍主题)。
如果情况正相反——种类频繁变、族很稳定,抽象工厂会让你举步维艰。
注意
经验法则:横轴(产品种类)稳定、纵轴(产品族)易变时,抽象工厂最舒服。反过来就别硬套。
正在加载概念检查...
正在加载本节练习...