一、设计模式中的“百变魔君”:抽象工厂模式概述
在软件设计的武林中,抽象工厂模式就像那位擅长百变的魔君,不仅能一键变装,还能连带着小弟们一起换个模样。
它的核心意图是:“提供一个创建一组相关或相互依赖对象的接口,而无需指定它们的具体类。”
简单来说,抽象工厂是一系列工厂方法的工厂。你要啥?一整套都给你打包带走。
看起来霸道,实则脆弱。 为什么?因为抽象工厂涉及到:
- 产品族和产品等级的复杂耦合
- 接口泛滥,类层级爆炸
- 新增产品困难,容易设计僵化
- 和依赖注入结合不自然
- 往往陷入“过度设计”之坑
二、实现方式
1. 简单抽象工厂:粗暴直给
public interface IButton
{
void Render();
}
public interface ICheckbox
{
void Render();
}
public interface IGUIFactory
{
IButton CreateButton();
ICheckbox CreateCheckbox();
}
public class WinFactory : IGUIFactory
{
public IButton CreateButton() => new WinButton();
public ICheckbox CreateCheckbox() => new WinCheckbox();
}
public class MacFactory : IGUIFactory
{
public IButton CreateButton() => new MacButton();
public ICheckbox CreateCheckbox() => new MacCheckbox();
}
✅ 优点:
- 统一产品族,减少“拼盘”组合带来的管理难度
- 工厂接口隔离,扩展工厂时不影响客户端
❌ 缺点:
- 复杂且脆弱:要增加产品族?抱歉,得多写好几个类和接口
- 难以应对变更:产品等级一变,所有工厂跟着改
2. 抽象工厂 + 依赖注入
public class UIFactoryService
{
private readonly IGUIFactory _factory;
public UIFactoryService(IGUIFactory factory)
{
_factory = factory;
}
public void RenderUI()
{
var button = _factory.CreateButton();
var checkbox = _factory.CreateCheckbox();
button.Render();
checkbox.Render();
}
}
✅ 优点:
- 和依赖注入兼容:通过构造函数注入,灵活更换工厂
- 测试方便:可以 mock 工厂接口
❌ 缺点:
- 接口冗余:需要维护大量接口,心累
三、抽象工厂的适用场景:别看热闹,不要乱用
抽象工厂适合 “多个产品族切换” 的场景。以下情况可以考虑:
✅ 适用场景:
- 跨平台 UI 构建:比如 Win 和 Mac 两种 UI 控件集合
- 插件扩展机制:不同厂商的驱动适配
- 主题样式切换:比如暗黑模式和亮色模式组件
- 游戏开发:不同种族兵种(比如人族和兽族)
- 设备适配:比如 PC 和移动设备的组件库
❌ 反模式警告:滥用抽象工厂
如果你的场景只有单一产品族或单一产品等级,还非要搞抽象工厂,那最终你会陷入接口套接口的地狱,代码变得臃肿又繁琐。
四、总结
抽象工厂的使用在于:
- 稳定性和扩展性不可兼得:过于追求抽象反而失去灵活
- 灵活的抽象才是王道:和依赖注入结合才能发挥最大价值
- 不要为抽象而抽象:很多场景下,一个简单工厂就够用了