本文为设计模式系列第6篇,聚焦创建型模式中的抽象工厂模式,涵盖定义、原理、实际业务场景、优缺点、最佳实践及详细代码示例,适合系统学习与实战应用。
目录
1. 模式概述
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式。它为创建一组相关或相互依赖的对象提供一个接口,而无需指定它们的具体类。抽象工厂模式是工厂方法模式的扩展,适合产品族的统一创建和兼容性保障。
1.1 定义
为创建一系列相关或相互依赖对象提供一个接口,而无需指定它们的具体类。
1.2 目的
- 创建产品族,保证产品间兼容性
- 封装产品创建细节,简化客户端
- 支持系统扩展和平台切换
2. 使用场景
抽象工厂模式在实际开发中应用广泛,常见场景包括:
- 跨平台UI框架:如Windows、Mac、Linux等不同风格控件的统一创建。
- 数据库访问层:如支持多种数据库(MySQL、Oracle、SQL Server),统一数据访问接口。
- 游戏开发:如不同场景、角色、道具的批量创建,保证风格一致。
- 产品系列扩展:如不同品牌、不同版本的产品族扩展。
真实业务背景举例:
- 跨平台桌面应用需根据操作系统切换UI风格,抽象工厂统一创建控件,保证界面一致性。
- 企业级系统需支持多种数据库,抽象工厂屏蔽底层差异,便于切换和维护。
- 游戏引擎根据不同主题批量生成角色、道具,保证风格统一。
3. 优缺点分析
3.1 优点
- 产品兼容性:保证同一工厂生产的产品风格一致,避免不兼容。
- 封装性:隐藏产品创建细节,客户端只依赖抽象接口。
- 扩展性:易于新增产品族,符合开闭原则。
3.2 缺点
- 类数量增加:每个产品族和产品类型都需新增类,结构复杂。
- 扩展单一产品困难:新增产品类型需修改工厂接口,违反开闭原则。
- 适用范围有限:只适用于产品族创建,不适合单一产品扩展。
4. 实际应用案例
- UI框架:Windows、Mac、Linux等风格控件的统一创建。
- 数据库访问:多数据库支持,统一数据访问接口。
- 游戏开发:不同主题下的角色、道具、场景批量生成。
- 品牌产品线:如家电、汽车等不同品牌/系列的产品族。
5. 结构与UML类图
@startuml
package "Abstract Factory Pattern" #DDDDDD {
interface Button {
+ render(): void
}
interface TextBox {
+ render(): void
}
class WindowsButton implements Button
class WindowsTextBox implements TextBox
class MacButton implements Button
class MacTextBox implements TextBox
interface UIFactory {
+ createButton(): Button
+ createTextBox(): TextBox
}
class WindowsUIFactory implements UIFactory
class MacUIFactory implements UIFactory
class Client
UIFactory <|.. WindowsUIFactory
UIFactory <|.. MacUIFactory
Button <|.. WindowsButton
Button <|.. MacButton
TextBox <|.. WindowsTextBox
TextBox <|.. MacTextBox
WindowsUIFactory --> WindowsButton : createButton()
WindowsUIFactory --> WindowsTextBox : createTextBox()
MacUIFactory --> MacButton : createButton()
MacUIFactory --> MacTextBox : createTextBox()
Client ..> UIFactory : uses
}
@enduml
6. 代码示例
6.1 基本结构示例
业务背景: 跨平台UI库需支持不同操作系统风格的控件统一创建。
// 抽象产品:按钮和文本框
public interface Button {
void render();
}
public interface TextBox {
void render();
}
// Windows风格产品
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("[Windows] 渲染按钮");
}
}
public class WindowsTextBox implements TextBox {
@Override
public void render() {
System.out.println("[Windows] 渲染文本框");
}
}
// Mac风格产品
public class MacButton implements Button {
@Override
public void render() {
System.out.println("[Mac] 渲染按钮");
}
}
public class MacTextBox implements TextBox {
@Override
public void render() {
System.out.println("[Mac] 渲染文本框");
}
}
// 抽象工厂接口
public interface UIFactory {
Button createButton();
TextBox createTextBox();
}
// Windows工厂
public class WindowsUIFactory implements UIFactory {
public Button createButton() { return new WindowsButton(); }
public TextBox createTextBox() { return new WindowsTextBox(); }
}
// Mac工厂
public class MacUIFactory implements UIFactory {
public Button createButton() { return new MacButton(); }
public TextBox createTextBox() { return new MacTextBox(); }
}
// 客户端示例
public class Client {
public static void main(String[] args) {
UIFactory factory = new WindowsUIFactory();
Button button = factory.createButton();
TextBox textBox = factory.createTextBox();
button.render();
textBox.render();
// 切换风格只需更换工厂
factory = new MacUIFactory();
button = factory.createButton();
textBox = factory.createTextBox();
button.render();
textBox.render();
}
// 总结:通过抽象工厂,客户端无需关心具体产品实现,便于扩展和维护。
}
6.2 实际业务场景:数据库访问工厂
业务背景: 企业系统需支持多种数据库,抽象工厂统一创建数据访问对象,屏蔽底层差异。
// 抽象产品:数据库连接和命令
public interface DBConnection {
void connect();
}
public interface DBCommand {
void execute(String sql);
}
// MySQL产品
public class MySQLConnection implements DBConnection {
public void connect() { System.out.println("[MySQL] 连接数据库"); }
}
public class MySQLCommand implements DBCommand {
public void execute(String sql) { System.out.println("[MySQL] 执行SQL: " + sql); }
}
// Oracle产品
public class OracleConnection implements DBConnection {
public void connect() { System.out.println("[Oracle] 连接数据库"); }
}
public class OracleCommand implements DBCommand {
public void execute(String sql) { System.out.println("[Oracle] 执行SQL: " + sql); }
}
// 抽象工厂
public interface DBFactory {
DBConnection createConnection();
DBCommand createCommand();
}
// MySQL工厂
public class MySQLFactory implements DBFactory {
public DBConnection createConnection() { return new MySQLConnection(); }
public DBCommand createCommand() { return new MySQLCommand(); }
}
// Oracle工厂
public class OracleFactory implements DBFactory {
public DBConnection createConnection() { return new OracleConnection(); }
public DBCommand createCommand() { return new OracleCommand(); }
}
// 客户端示例
public class DBClient {
public static void main(String[] args) {
DBFactory factory = new MySQLFactory();
DBConnection conn = factory.createConnection();
DBCommand cmd = factory.createCommand();
conn.connect();
cmd.execute("SELECT * FROM user");
// 切换数据库只需更换工厂
factory = new OracleFactory();
conn = factory.createConnection();
cmd = factory.createCommand();
conn.connect();
cmd.execute("SELECT * FROM user");
}
}
7. 测试用例
业务背景: 验证UI工厂和数据库工厂的多实现切换与功能正确性。
public class AbstractFactoryPatternTest {
@Test
public void testWindowsUI() {
UIFactory factory = new WindowsUIFactory();
Button button = factory.createButton();
assertTrue(button instanceof WindowsButton);
TextBox textBox = factory.createTextBox();
assertTrue(textBox instanceof WindowsTextBox);
}
@Test
public void testMacUI() {
UIFactory factory = new MacUIFactory();
Button button = factory.createButton();
assertTrue(button instanceof MacButton);
TextBox textBox = factory.createTextBox();
assertTrue(textBox instanceof MacTextBox);
}
@Test
public void testDBFactory() {
DBFactory factory = new MySQLFactory();
DBConnection conn = factory.createConnection();
DBCommand cmd = factory.createCommand();
assertTrue(conn instanceof MySQLConnection);
assertTrue(cmd instanceof MySQLCommand);
factory = new OracleFactory();
conn = factory.createConnection();
cmd = factory.createCommand();
assertTrue(conn instanceof OracleConnection);
assertTrue(cmd instanceof OracleCommand);
}
}
8. 常见误区与反例
- 误区1:工厂类职责过重,变成"万能工厂"。
应按产品族拆分工厂,避免单一工厂膨胀。 - 误区2:客户端仍直接依赖具体产品。
应通过工厂接口获取产品,避免高耦合。 - 反例:产品族扩展困难。
抽象工厂适合产品族整体扩展,不适合单一产品扩展。
9. 最佳实践
- 接口设计:工厂和产品接口要简洁,便于扩展和维护。
- 工厂拆分:按产品族或业务领域拆分工厂,避免"万能工厂"。
- 异常与资源管理:工厂方法应妥善处理异常和资源释放。
- 扩展性:新增产品族时优先扩展工厂,不修改已有代码。
- 文档和UML同步:保持文档、UML和代码示例一致,便于团队协作。
10. 参考资料与延伸阅读
- 《设计模式:可复用面向对象软件的基础》GoF
- Effective Java(中文版)
- https://refactoringguru.cn/design-patterns/abstract-factory
- https://www.baeldung.com/java-abstract-factory-pattern
本文为设计模式系列第6篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。