HelloWorld 抽象工厂教程
2026年6月30日
•
作者:admin
抽象工厂(Abstract Factory)就是:把创建一族相关或相互依赖对象的工作交给一个“工厂簇”,客户端只要告诉它需要哪一簇,就能得到匹配的一组产品。把“HelloWorld”拆成不同语言的问候、样式和输出渠道,抽象工厂可以一次性提供整套对应的实现,便于切换语言、统一配置和扩展而不改动业务代码。

为什么要用抽象工厂?先讲个日常比喻
想象你在一家跨国连锁咖啡店工作。每到一个国家,你要做的不是单独买杯咖啡、买杯子、买吸管,而是要按“国家套餐”一次性拿齐——杯子类型、配方、包装语、收据语言都匹配。抽象工厂就是这个“国家套餐”的管理者:你只选择“哪个国家”,就能得到一致的、一套配好的对象。
核心意图(一句话)
抽象工厂的目标是提供一个接口,用于创建相关或相互依赖对象的家族,而无需指定它们的具体类。
抽象工厂的组成要素(用最简单的词解释)
- 抽象工厂接口:定义创建一组产品的方法。
- 具体工厂:实现抽象工厂,创建某一产品家族的具体对象。
- 抽象产品接口:每个产品种类(比如“问候语”“格式化器”)有自己的抽象接口。
- 具体产品:实现抽象产品接口的具体类,属于某一工厂家族。
- 客户端:通过抽象工厂和抽象产品接口使用对象,不依赖具体实现。
用一句话理解职责分离
工厂负责“怎么产”,客户端负责“用什么”,产品只负责“干什么”。这样换语言或样式,只改工厂,不改客户端。
HelloWorld 实战:按语言切换整套问候方案
目标很直接:构建一个系统,能够根据“语言工厂”生成一整套与该语言相关的问候组件(比如 Greeting、Formatter、Output),客户端只获取抽象接口并调用,能动态切换中文、英文、日文等实现。
参与者表(职责一览)
| 参与者 | 职责 |
| AbstractFactory | 提供创建 Greeting, Formatter, Output 等方法 |
| ConcreteFactory (e.g., ChineseFactory) | 生产中文实现的 Greeting/Formatter/Output |
| AbstractProduct (Greeting) | 定义 sayHello() 等行为 |
| ConcreteProduct (ChineseGreeting) | 实现具体问候逻辑,如“你好,世界” |
| Client | 通过抽象工厂获取产品并使用,不关心具体类 |
Java 示例(结构清晰,便于理解)
这里展现最关键的类与接口,省略包和 import。读着就像在搭积木。
// 抽象产品:问候
public interface Greeting {
String say();
}
// 抽象产品:格式化器
public interface Formatter {
String format(String message);
}
// 抽象产品:输出器
public interface Output {
void out(String content);
}
// 抽象工厂
public interface HelloFactory {
Greeting createGreeting();
Formatter createFormatter();
Output createOutput();
}
// 中文具体产品与工厂
public class ChineseGreeting implements Greeting {
public String say() { return "你好,世界"; }
}
public class ChineseFormatter implements Formatter {
public String format(String message) { return "【问候】" + message; }
}
public class ConsoleOutput implements Output {
public void out(String content) { System.out.println(content); }
}
public class ChineseFactory implements HelloFactory {
public Greeting createGreeting() { return new ChineseGreeting(); }
public Formatter createFormatter() { return new ChineseFormatter(); }
public Output createOutput() { return new ConsoleOutput(); }
}
// 客户端
public class Client {
private HelloFactory factory;
public Client(HelloFactory f) { this.factory = f; }
public void greet() {
Greeting g = factory.createGreeting();
Formatter fm = factory.createFormatter();
Output out = factory.createOutput();
out.out(fm.format(g.say()));
}
}
// 使用
HelloFactory factory = new ChineseFactory();
new Client(factory).greet();
说明(为什么这样设计)
- 客户端仅依赖 HelloFactory 与抽象产品,切换语言只需注入不同的工厂实例。
- 增加新语言时只需新增一组具体产品和对应工厂,其他代码不变。
- 保证同一套输出是一致的:比如 Formatter 与 Greeting 配套使用,避免语言混杂。
Python 版本(更简洁,利于快速原型)
from abc import ABC, abstractmethod
class Greeting(ABC):
@abstractmethod
def say(self): pass
class Formatter(ABC):
@abstractmethod
def format(self, message): pass
class Output(ABC):
@abstractmethod
def out(self, content): pass
class HelloFactory(ABC):
@abstractmethod
def create_greeting(self): pass
@abstractmethod
def create_formatter(self): pass
@abstractmethod
def create_output(self): pass
# 中文实现
class ChineseGreeting(Greeting):
def say(self): return "你好,世界"
class ChineseFormatter(Formatter):
def format(self, message): return f"【问候】{message}"
class ConsoleOutput(Output):
def out(self, content): print(content)
class ChineseFactory(HelloFactory):
def create_greeting(self): return ChineseGreeting()
def create_formatter(self): return ChineseFormatter()
def create_output(self): return ConsoleOutput()
# 客户端
def client(factory: HelloFactory):
g = factory.create_greeting()
f = factory.create_formatter()
o = factory.create_output()
o.out(f.format(g.say()))
client(ChineseFactory())
常见误区与把控点(写给会动手的人)
- 误区一:把抽象工厂当成单例工厂来用。单例可以,但要注意状态与线程安全。
- 误区二:过度设计——如果只有一种产品,使用抽象工厂反而增加复杂度。
- 把控点:确定“产品族”的边界。哪些对象必须成套替换?把这些对象抽象为同一工厂的产品。
何时用抽象工厂而非简单工厂或建造者
- 当你需要创建一组相互关联的对象,并且希望保证不同实现之间的一致性时,选抽象工厂。
- 当构建过程本身复杂、按步骤生成同一个对象的不同部分时,建造者更合适。
- 简单工厂倾向于创建单一对象或少数几类,适用性更窄。
扩展技巧与实践建议(有点实战味道)
- 解耦配置与实现:把工厂的选择交给配置文件或 DI 容器,运行时切换语言/风格。
- 工厂组合:当产品族很大时,可以把工厂分层,例如:BaseFactory + ThemeFactory。
- 测试友好:工厂接口便于注入测试专用的 Mock 工厂,从而把依赖控制在测试范围内。
- 状态控制:尽量让具体产品无状态或轻状态,避免工厂创建带有全局副作用的对象。
性能与可维护性的权衡
抽象工厂提高了可维护性与扩展性,但也会带来类数量的增加和间接调用的开销。通常这类开销在业务层面是微不足道的,除非工厂在高频循环内反复创建昂贵对象。实践中可以通过对象池、缓存或将工厂置为单例来优化。
一些我个人常用的小技巧(边写边想的那种)
- 初期先用简单工厂快速迭代,确定产品族边界后再引入抽象工厂重构。
- 把“格式化”“路由”“本地化资源”这种横切关注点设计为产品接口,能避免后续大量修改。
- 在代码里加上工厂和产品之间的契约注释,例如预期的字符集、是否为异步输出等,能省很多沟通成本。
参考书目(可进一步深入)
- Gamma, Helm, Johnson, Vlissides — Design Patterns: Elements of Reusable Object-Oriented Software
- Martin Fowler — Patterns of Enterprise Application Architecture
- 《设计模式 —— 可复用面向对象软件的基础》
就先写到这儿吧。用抽象工厂把 HelloWorld 做成“语言套餐”是个很自然的切分,既保证了整套输出的一致性,也方便扩展和测试。实际工程中,记得先验证产品族边界、再根据频率和性能考虑是否做缓存或单例,别一开始就把所有模式都用上,否则折腾得不值。
相关文章
了解更多相关内容