设计模式:抽象工厂模式

32 阅读2分钟

一、设计模式中的“百变魔君”:抽象工厂模式概述

在软件设计的武林中,抽象工厂模式就像那位擅长百变的魔君,不仅能一键变装,还能连带着小弟们一起换个模样。

它的核心意图是:“提供一个创建一组相关或相互依赖对象的接口,而无需指定它们的具体类。

简单来说,抽象工厂是一系列工厂方法的工厂。你要啥?一整套都给你打包带走。

看起来霸道,实则脆弱。 为什么?因为抽象工厂涉及到:

  • 产品族和产品等级的复杂耦合
  • 接口泛滥,类层级爆炸
  • 新增产品困难,容易设计僵化
  • 和依赖注入结合不自然
  • 往往陷入“过度设计”之坑

二、实现方式

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 工厂接口
缺点
  • 接口冗余:需要维护大量接口,心累

三、抽象工厂的适用场景:别看热闹,不要乱用

抽象工厂适合 “多个产品族切换” 的场景。以下情况可以考虑:

适用场景:
  1. 跨平台 UI 构建:比如 Win 和 Mac 两种 UI 控件集合
  2. 插件扩展机制:不同厂商的驱动适配
  3. 主题样式切换:比如暗黑模式和亮色模式组件
  4. 游戏开发:不同种族兵种(比如人族和兽族)
  5. 设备适配:比如 PC 和移动设备的组件库
反模式警告:滥用抽象工厂

如果你的场景只有单一产品族或单一产品等级,还非要搞抽象工厂,那最终你会陷入接口套接口的地狱,代码变得臃肿又繁琐。


四、总结

抽象工厂的使用在于:

  • 稳定性和扩展性不可兼得:过于追求抽象反而失去灵活
  • 灵活的抽象才是王道:和依赖注入结合才能发挥最大价值
  • 不要为抽象而抽象:很多场景下,一个简单工厂就够用了