HelloWorld 工厂模式指南

工厂模式把“怎么造对象”这个决定从使用者手里拿过来,放到一个专门负责造东西的地方;这样客户端只关心“我要一个HelloWorld”,不必知道具体类名或创建细节,提升模块独立性和扩展能力。本指南用HelloWorld示例拆解简单工厂、工厂方法与抽象工厂,讲清什么时候用、怎么写、常见陷阱与测试策略,便于你在真实项目里放心应用、逐步演进。

HelloWorld 工厂模式指南

先弄清一个直观比喻

想象你去咖啡店点咖啡:你只说“来一杯拿铁”,不需要知道豆子产地、烘焙温度或机器型号。咖啡店就是“工厂”,它负责把原料和机器组装成一杯可喝的咖啡。工厂模式就是把创建对象的细节封装起来,让使用者只关心接口或抽象。

为什么要用工厂模式?

  • 解耦:客户端不直接依赖具体类,便于替换实现。
  • 集中创建逻辑:构造过程复杂时,把这部分放在工厂里更清晰。
  • 易于扩展:新增产品通常只需修改或扩展工厂,不影响客户端。
  • 便于测试:能把工厂替换为测试桩(stub)或模拟(mock)。

三种常见变体和它们的精髓

1. 简单工厂(Simple Factory)

不是标准 GoF 模式目录里的名字,但常见。用一个静态方法或者单例类,根据参数返回不同的具体对象。适合产品族少、创建规则集中且不会频繁变动的场景。

  • 优点:实现简单、调用方便。
  • 缺点:当产品种类增加时,工厂会膨胀,违反单一职责。

2. 工厂方法(Factory Method)

把创建方法定义在抽象工厂接口中,由具体工厂决定生产哪种产品。更符合开闭原则,新增产品通常通过新增具体工厂类实现。

3. 抽象工厂(Abstract Factory)

用于创建相关或相互依赖的一组对象,例如创建一套 UI 皮肤(按钮、输入框、菜单等)。抽象工厂提供接口,具体工厂生产一整套互相兼容的产品。

HelloWorld 示例:一步步来看(思路 > 代码)

先讲思路,再看实现。目标很简单:客户端调用工厂获得一个实现了 sayHello() 的对象,然后调用它输出“Hello, World”。

模式 核心要点 示例伪代码(简洁)
简单工厂 一个方法选择并返回具体产品

create(type) { if type==A return new HelloA(); else return new HelloB(); }

工厂方法 抽象工厂接口,子类重写创建方法

class Factory { create() abstract } class AFactory extends Factory { create() return HelloA }

抽象工厂 创建相关产品族(若有多个相关接口)

interface UIFactory { createButton(); createText(); } // choose LightFactory or DarkFactory

Java 风格:工厂方法(简化版)

概念清楚后,代码就是按职责分层。下面是思路版(伪代码),便于把握结构。

  • 接口:Hello { void say(); }
  • 实现:HelloEn、HelloCn 等
  • 抽象工厂:HelloFactory { Hello create(); }
  • 具体工厂:EnFactory、CnFactory
  • 客户端:factory.create().say();

Python 风格:简洁的简单工厂

Python 可以用字典映射把简单工厂写得很短,但要注意可测试性与扩展性。

常见使用场景与决策树(实用指南)

  • 如果只有一种创建点且产品种类可能变化,但创建逻辑集中:用简单工厂先行。
  • 如果需要不同模块决定如何创建对象,或有多个并行创建者:选工厂方法
  • 如果要创建互相关联的多种产品(产品族):用抽象工厂
  • 如果你已经在使用依赖注入容器(DI):有时工厂可由容器管理,避免手写工厂。

性能、线程安全与延迟创建的小贴士

  • 工厂通常很轻量,若只是创建简单对象,性能问题少见。
  • 如果工厂内部维护共享可变状态,必须考虑并发访问和同步。
  • 懒加载(lazy init)可以与工厂结合:在第一次请求时创建单例,但注意双重检查锁定的正确实现。

测试策略:如何方便地测试依赖工厂的代码

测试时的原则是替换外部依赖。对工厂模式而言:

  • 把工厂注入到客户端(构造器注入),不要在方法里直接 new。
  • 在单元测试中用测试工厂返回轻量或可断言的对象。
  • 如果使用静态工厂方法,可以通过包装或引入工厂接口来提高可替换性。

常见陷阱(来自实际项目的教训)

  • 过度设计:为简单用例引入抽象工厂/接口会增加复杂度,别为了模式而模式化。
  • 职责混淆:不要让工厂做太多工作(比如同时负责配置解析、网络请求等),否则又回到大而全的类。
  • 隐式依赖:工厂内部依赖如果不显式注入,会造成难以测试的代码。
  • 版本演化痛点:当产品构造需要新参数时,工厂接口可能需要演进,设计时要预留扩展点或使用构建者模式配合。

迁移与重构建议(当代码里已经有大量 new)

  • 先从最常变的地方着手:把这些 new 提取到工厂,替换调用点。
  • 逐步引入抽象:先引入接口与默认工厂实现,再在需要处替换。
  • 写好测试套件:重构前后行为一致性由测试保障。

设计细节与进阶话题

几点值得记住的实践细节:

  • 参数化工厂:当对象构建依赖于运行时参数时,让工厂方法带参数而不是在外面做复杂拼装。
  • 注册/映射表:工厂内部可以使用注册机制(map key -> creator),便于运行时扩展(插件式)。
  • 结合依赖注入:现代框架的容器能把工厂注册为服务,省去手写工厂的样板代码。
  • 工厂返回接口而非具体类:这点很重要,保证客户端能被替换不同实现而不改动。

快速参考表:何时选哪个?

场景 推荐模式 理由
产品种类少、构造集中 简单工厂 实现简单,便于集中管理
需要子类决定如何创建 工厂方法 符合开闭原则,易扩展
一组相关产品需一起创建 抽象工厂 保证产品族之间兼容性

最后一点:从 HelloWorld 做到生产级应用

HelloWorld 的示例很简单,但实际应用里你会遇到配置、依赖、生命周期管理、错误处理与性能需求。把这些问题拆成小块:先让工厂只负责创建并注入基本依赖,再逐步把复杂逻辑迁移到更专门的组件;必要时结合构建者(Builder)或依赖注入框架,保持代码可测试、易演进。嗯,说着说着,可能你已经有个想法要怎么改项目里那处乱七八糟的 new 了,我也是这么一步步改过来的。

返回首页