简单工厂不是设计模式,因违反开闭原则且未被GoF收录;抽象工厂才是,它通过抽象接口解耦产品族创建,支持跨平台、多数据库等场景,需配合依赖注入与清晰的产品族设计。

简单工厂不是设计模式,抽象工厂才是;想解耦依赖,别用简单工厂硬套,它会悄悄把你拉回紧耦合的坑里。
为什么简单工厂 SimpleFactory 不能算设计模式
它没有被收录进 GoF 23 种经典模式——根本原因在于它违反了“开闭原则”:每新增一个产品类,就得修改 SimpleFactory.Create() 方法里的 switch 或 if 分支。一旦逻辑变复杂,这个方法就成了上帝方法,测试难、扩展难、上线改一行都得全量回归。
常见错误现象:NullReferenceException 频发,但根源是工厂返回了 null(比如传错类型名),而调用方没做判空——因为大家都默认“工厂就该兜底”,结果把防御性编程责任转嫁给了下游。
- 它适合教学演示或原型阶段,不适合中大型项目的核心对象创建路径
- 它不解决依赖倒置,只是把
new搬到了一个地方,本质仍是“依赖具体类” - 如果你正在写单元测试,
SimpleFactory会让Mock变得极其别扭——你得去Mock工厂本身,而不是接口
抽象工厂 AbstractFactory 怎么真正解耦
核心是定义创建一族相关或相互依赖对象的接口,且不指定具体类。客户端只依赖抽象工厂和抽象产品,运行时由子类工厂决定实例化哪个组合。
典型使用场景:跨平台 UI 控件(WinButton / MacButton)、数据库访问层适配(SqlServerFactory / MySqlFactory)。
- 必须先定义抽象产品接口,如
IButton、;再定义抽象工厂 <code>IWidgetFactory,含CreateButton()和CreateTextBox() - 每个具体工厂(如
WinFactory)实现全部创建方法,确保返回的对象属于同一“家族”,避免混搭出错 - 注入方式推荐构造函数注入:把
IWidgetFactory当作参数传入业务类,而非在类内部new WinFactory()
示例片段:
public interface IButton { void Render(); }
public interface ITextBox { void Render(); }
public interface IWidgetFactory {
IButton CreateButton();
ITextBox CreateTextBox();
}
public class WinFactory : IWidgetFactory {
public IButton CreateButton() => new WinButton();
public ITextBox CreateTextBox() => new WinTextBox();
}
public class ThemeController {
private readonly IWidgetFactory _factory;
public ThemeController(IWidgetFactory factory) => _factory = factory;
public void Draw() {
_factory.CreateButton().Render();
_factory.CreateTextBox().Render();
}
}
抽象工厂的性能与兼容性注意点
抽象工厂本身几乎没有运行时开销,但它的价值取决于你怎么组织“产品族”。如果一个工厂返回 10 个产品,而某处只用其中 1 个,说明接口粒度太粗,违背了接口隔离原则——这时应拆分成多个小工厂,或改用工厂方法模式(FactoryMethod)。
- .NET 6+ 推荐配合
Microsoft.Extensions.DependencyInjection注册:把IWidgetFactory和具体实现注册为Scoped或Transient,避免手动new - 不要让抽象工厂承担对象生命周期管理(比如缓存单例实例),那是
IServiceProvider或自定义ObjectPool的事 - 如果产品族需要动态切换(如用户换主题),别在构造时固化工厂实例——改用
Func<iwidgetfactory></iwidgetfactory>或IOptionsSnapshot<themeconfig></themeconfig>延迟解析
什么时候该放弃抽象工厂,选别的方案
当你发现为了满足抽象工厂的“一族约束”,不得不造一堆空实现、抛 NotSupportedException,或者不同产品之间根本不存在逻辑关联(比如同时创建 Logger 和 HttpClient),那抽象工厂就是过度设计。
- 单一对象创建 → 优先用依赖注入容器(
IServiceCollection.AddSingleton<irepository sqlrepo>()</irepository>) - 创建逻辑复杂且需复用 → 工厂方法模式(
Creator类定义CreateProduct()抽象方法,子类实现) - 需要延迟初始化 + 共享实例 → 直接用
Lazy<t></t>或Singleton<t></t>模式
抽象工厂真正的门槛不在代码怎么写,而在你能不能清晰画出那张“产品族关系图”——图没想清楚,代码越写越像拼图游戏。


















