1.项目结构
bash
abstract-factory-demo/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── abstractfactory/
│ │ │ ├── factory/
│ │ │ │ ├── GUIFactory.java
│ │ │ │ ├── MacOSFactory.java
│ │ │ │ └── WindowsFactory.java
│ │ │ ├── buttons/
│ │ │ │ ├── Button.java
│ │ │ │ ├── MacOSButton.java
│ │ │ │ └── WindowsButton.java
│ │ │ ├── checkboxes/
│ │ │ │ ├── Checkbox.java
│ │ │ │ ├── MacOSCheckbox.java
│ │ │ │ └── WindowsCheckbox.java
│ │ │ ├── textfields/
│ │ │ │ ├── TextField.java
│ │ │ │ ├── MacOSTextField.java
│ │ │ │ └── WindowsTextField.java
│ │ │ ├── application/
│ │ │ │ └── Application.java
│ │ │ └── Main.java
│ │ └── resources/
│ └── test/
│ └── java/
│ └── com/
│ └── example/
│ └── abstractfactory/
│ └── AbstractFactoryTest.java
2.代码实现
-
Maven配置文件 (pom.xml)
xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>abstract-factory-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- JUnit for testing --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project> -
抽象产品接口
按钮接口 (Button.java):
javapackage com.example.abstractfactory.buttons; /** * 抽象产品:按钮接口 */ public interface Button { void paint(); void click(); String getDescription(); }复选框接口 (Checkbox.java):
javapackage com.example.abstractfactory.checkboxes; /** * 抽象产品:复选框接口 */ public interface Checkbox { void paint(); void check(); boolean isChecked(); String getDescription(); }文本框接口 (TextField.java):
javapackage com.example.abstractfactory.textfields; /** * 抽象产品:文本框接口 */ public interface TextField { void paint(); void setText(String text); String getText(); String getDescription(); } -
具体实现
Windows按钮 (WindowsButton.java):
javapackage com.example.abstractfactory.buttons; /** * 具体产品:Windows按钮 */ public class WindowsButton implements Button { private boolean clicked = false; @Override public void paint() { System.out.println("渲染Windows风格按钮"); System.out.println("┌─────────────────┐"); System.out.println("│ Windows按钮 │"); System.out.println("└─────────────────┘"); } @Override public void click() { clicked = true; System.out.println("Windows按钮被点击"); System.out.println("执行Windows系统相关操作..."); } @Override public String getDescription() { return "Windows风格按钮"; } public boolean isClicked() { return clicked; } }MacOS按钮 (MacOSButton.java):
javapackage com.example.abstractfactory.buttons; /** * 具体产品:MacOS按钮 */ public class MacOSButton implements Button { private boolean clicked = false; @Override public void paint() { System.out.println("渲染MacOS风格按钮"); System.out.println("╭─────────────────╮"); System.out.println("│ MacOS按钮 │"); System.out.println("╰─────────────────╯"); } @Override public void click() { clicked = true; System.out.println("MacOS按钮被点击"); System.out.println("执行MacOS系统相关操作..."); } @Override public String getDescription() { return "MacOS风格按钮"; } public boolean isClicked() { return clicked; } }Windows复选框 (WindowsCheckbox.java):
javapackage com.example.abstractfactory.checkboxes; /** * 具体产品:Windows复选框 */ public class WindowsCheckbox implements Checkbox { private boolean checked = false; @Override public void paint() { System.out.println("渲染Windows风格复选框"); System.out.println("□ Windows复选框 " + (checked ? "[已选中]" : "[未选中]")); } @Override public void check() { checked = !checked; System.out.println("Windows复选框状态: " + (checked ? "选中" : "未选中")); } @Override public boolean isChecked() { return checked; } @Override public String getDescription() { return "Windows风格复选框"; } }MacOS复选框 (MacOSCheckbox.java):
javapackage com.example.abstractfactory.checkboxes; /** * 具体产品:MacOS复选框 */ public class MacOSCheckbox implements Checkbox { private boolean checked = false; @Override public void paint() { System.out.println("渲染MacOS风格复选框"); System.out.println("☐ MacOS复选框 " + (checked ? "[✓]" : "[ ]")); } @Override public void check() { checked = !checked; System.out.println("MacOS复选框状态: " + (checked ? "✓" : "空")); } @Override public boolean isChecked() { return checked; } @Override public String getDescription() { return "MacOS风格复选框"; } }Windows文本框 (WindowsTextField.java):
javapackage com.example.abstractfactory.textfields; /** * 具体产品:Windows文本框 */ public class WindowsTextField implements TextField { private String text = ""; @Override public void paint() { System.out.println("渲染Windows风格文本框"); System.out.println("┌─────────────────────────────┐"); System.out.println("│ │"); System.out.println("│ " + (text.isEmpty() ? "请输入..." : text) + String.format("%" + (25 - text.length()) + "s", "") + "│"); System.out.println("│ │"); System.out.println("└─────────────────────────────┘"); } @Override public void setText(String text) { this.text = text; System.out.println("Windows文本框内容设置为: " + text); } @Override public String getText() { return text; } @Override public String getDescription() { return "Windows风格文本框"; } }MacOS文本框 (MacOSTextField.java):
javapackage com.example.abstractfactory.textfields; /** * 具体产品:MacOS文本框 */ public class MacOSTextField implements TextField { private String text = ""; @Override public void paint() { System.out.println("渲染MacOS风格文本框"); System.out.println("╭─────────────────────────────╮"); System.out.println("│ │"); System.out.println("│ " + (text.isEmpty() ? "Enter text..." : text) + String.format("%" + (25 - text.length()) + "s", "") + "│"); System.out.println("│ │"); System.out.println("╰─────────────────────────────╯"); } @Override public void setText(String text) { this.text = text; System.out.println("MacOS文本框内容设置为: " + text); } @Override public String getText() { return text; } @Override public String getDescription() { return "MacOS风格文本框"; } } -
抽象工厂和具体工厂
抽象工厂接口 (GUIFactory.java):
javapackage com.example.abstractfactory.factory; import com.example.abstractfactory.buttons.Button; import com.example.abstractfactory.checkboxes.Checkbox; import com.example.abstractfactory.textfields.TextField; /** * 抽象工厂:GUI工厂接口 * 声明一组创建相关产品的方法 */ public interface GUIFactory { Button createButton(); Checkbox createCheckbox(); TextField createTextField(); // 工厂描述 String getFactoryDescription(); }Windows工厂 (WindowsFactory.java):
javapackage com.example.abstractfactory.factory; import com.example.abstractfactory.buttons.Button; import com.example.abstractfactory.buttons.WindowsButton; import com.example.abstractfactory.checkboxes.Checkbox; import com.example.abstractfactory.checkboxes.WindowsCheckbox; import com.example.abstractfactory.textfields.TextField; import com.example.abstractfactory.textfields.WindowsTextField; /** * 具体工厂:Windows工厂 * 创建Windows风格的产品家族 */ public class WindowsFactory implements GUIFactory { @Override public Button createButton() { System.out.println("创建Windows风格按钮..."); return new WindowsButton(); } @Override public Checkbox createCheckbox() { System.out.println("创建Windows风格复选框..."); return new WindowsCheckbox(); } @Override public TextField createTextField() { System.out.println("创建Windows风格文本框..."); return new WindowsTextField(); } @Override public String getFactoryDescription() { return "Windows风格GUI工厂"; } }MacOS工厂 (MacOSFactory.java):
javapackage com.example.abstractfactory.factory; import com.example.abstractfactory.buttons.Button; import com.example.abstractfactory.buttons.MacOSButton; import com.example.abstractfactory.checkboxes.Checkbox; import com.example.abstractfactory.checkboxes.MacOSCheckbox; import com.example.abstractfactory.textfields.TextField; import com.example.abstractfactory.textfields.MacOSTextField; /** * 具体工厂:MacOS工厂 * 创建MacOS风格的产品家族 */ public class MacOSFactory implements GUIFactory { @Override public Button createButton() { System.out.println("创建MacOS风格按钮..."); return new MacOSButton(); } @Override public Checkbox createCheckbox() { System.out.println("创建MacOS风格复选框..."); return new MacOSCheckbox(); } @Override public TextField createTextField() { System.out.println("创建MacOS风格文本框..."); return new MacOSTextField(); } @Override public String getFactoryDescription() { return "MacOS风格GUI工厂"; } } -
客户端应用
应用类 (Application.java):
javapackage com.example.abstractfactory.application; import com.example.abstractfactory.buttons.Button; import com.example.abstractfactory.checkboxes.Checkbox; import com.example.abstractfactory.factory.GUIFactory; import com.example.abstractfactory.textfields.TextField; /** * 客户端应用 * 使用抽象工厂创建产品家族 */ public class Application { private Button button; private Checkbox checkbox; private TextField textField; private GUIFactory factory; public Application(GUIFactory factory) { this.factory = factory; System.out.println("初始化应用,使用工厂: " + factory.getFactoryDescription()); } public void createUI() { System.out.println("\n=== 创建用户界面 ==="); // 使用工厂创建产品家族 this.button = factory.createButton(); this.checkbox = factory.createCheckbox(); this.textField = factory.createTextField(); System.out.println("UI创建完成"); } public void renderUI() { System.out.println("\n=== 渲染用户界面 ==="); // 渲染所有组件 button.paint(); checkbox.paint(); textField.paint(); System.out.println("UI渲染完成"); } public void simulateUserInteraction() { System.out.println("\n=== 模拟用户交互 ==="); // 模拟用户点击按钮 System.out.println("1. 用户点击按钮:"); button.click(); // 模拟用户勾选复选框 System.out.println("\n2. 用户勾选复选框:"); checkbox.check(); // 再次勾选 System.out.println("\n3. 用户再次勾选复选框:"); checkbox.check(); // 模拟用户输入文本 System.out.println("\n4. 用户在文本框中输入:"); textField.setText("Hello, Abstract Factory!"); textField.paint(); } public void showComponentDescriptions() { System.out.println("\n=== 组件描述 ==="); System.out.println("按钮: " + button.getDescription()); System.out.println("复选框: " + checkbox.getDescription()); System.out.println("文本框: " + textField.getDescription()); } // Getters public Button getButton() { return button; } public Checkbox getCheckbox() { return checkbox; } public TextField getTextField() { return textField; } public GUIFactory getFactory() { return factory; } }主程序 (Main.java):
javapackage com.example.abstractfactory; import com.example.abstractfactory.application.Application; import com.example.abstractfactory.factory.GUIFactory; import com.example.abstractfactory.factory.MacOSFactory; import com.example.abstractfactory.factory.WindowsFactory; /** * 主程序 * 演示抽象工厂模式的使用 */ public class Main { /** * 根据配置选择工厂 */ private static GUIFactory configureFactory(String osType) { if ("windows".equalsIgnoreCase(osType)) { System.out.println("检测到Windows系统,创建Windows工厂"); return new WindowsFactory(); } else if ("mac".equalsIgnoreCase(osType)) { System.out.println("检测到MacOS系统,创建MacOS工厂"); return new MacOSFactory(); } else { throw new IllegalArgumentException("未知的操作系统类型: " + osType); } } /** * 运行应用 */ private static void runApplication(String osType) { System.out.println("\n" + "=".repeat(60)); System.out.println("启动应用 - 操作系统: " + osType.toUpperCase()); System.out.println("=".repeat(60)); try { // 配置工厂 GUIFactory factory = configureFactory(osType); // 创建应用 Application app = new Application(factory); // 创建UI app.createUI(); // 渲染UI app.renderUI(); // 模拟用户交互 app.simulateUserInteraction(); // 显示组件描述 app.showComponentDescriptions(); } catch (IllegalArgumentException e) { System.out.println("错误: " + e.getMessage()); } } /** * 演示跨平台UI一致性 */ private static void demonstrateCrossPlatformUI() { System.out.println("\n" + "=".repeat(60)); System.out.println("演示跨平台UI一致性"); System.out.println("=".repeat(60)); System.out.println("\n=== Windows平台 ==="); GUIFactory windowsFactory = new WindowsFactory(); Application windowsApp = new Application(windowsFactory); windowsApp.createUI(); windowsApp.showComponentDescriptions(); System.out.println("\n=== MacOS平台 ==="); GUIFactory macFactory = new MacOSFactory(); Application macApp = new Application(macFactory); macApp.createUI(); macApp.showComponentDescriptions(); System.out.println("\n关键点:"); System.out.println("1. 两个应用使用相同的接口"); System.out.println("2. 组件行为一致,但外观不同"); System.out.println("3. 切换平台只需更换工厂"); } public static void main(String[] args) { System.out.println("========== 抽象工厂模式演示 =========="); System.out.println("模式说明:"); System.out.println("1. GUIFactory是抽象工厂,定义创建产品家族的方法"); System.out.println("2. WindowsFactory和MacOSFactory是具体工厂"); System.out.println("3. Button/Checkbox/TextField是抽象产品"); System.out.println("4. Windows/MacOS实现是具体产品"); System.out.println("5. Application是客户端,通过抽象工厂使用产品"); // 运行Windows应用 runApplication("windows"); // 运行MacOS应用 runApplication("mac"); // 演示跨平台一致性 demonstrateCrossPlatformUI(); System.out.println("\n" + "=".repeat(60)); System.out.println("模式优势总结:"); System.out.println("1. 确保产品家族的兼容性"); System.out.println("2. 客户端代码与具体产品解耦"); System.out.println("3. 易于扩展新的产品家族"); System.out.println("4. 保证同一家族产品的一致性"); System.out.println("=".repeat(60)); } } -
单元测试 (AbstractFactoryTest.java)
javapackage com.example.abstractfactory; import com.example.abstractfactory.application.Application; import com.example.abstractfactory.buttons.Button; import com.example.abstractfactory.buttons.MacOSButton; import com.example.abstractfactory.buttons.WindowsButton; import com.example.abstractfactory.checkboxes.Checkbox; import com.example.abstractfactory.checkboxes.MacOSCheckbox; import com.example.abstractfactory.checkboxes.WindowsCheckbox; import com.example.abstractfactory.factory.GUIFactory; import com.example.abstractfactory.factory.MacOSFactory; import com.example.abstractfactory.factory.WindowsFactory; import com.example.abstractfactory.textfields.TextField; import com.example.abstractfactory.textfields.MacOSTextField; import com.example.abstractfactory.textfields.WindowsTextField; import org.junit.Test; import static org.junit.Assert.*; /** * 抽象工厂模式单元测试 */ public class AbstractFactoryTest { @Test public void testWindowsFactoryCreatesWindowsProducts() { GUIFactory factory = new WindowsFactory(); Button button = factory.createButton(); Checkbox checkbox = factory.createCheckbox(); TextField textField = factory.createTextField(); // 验证产品类型 assertTrue("按钮应为WindowsButton", button instanceof WindowsButton); assertTrue("复选框应为WindowsCheckbox", checkbox instanceof WindowsCheckbox); assertTrue("文本框应为WindowsTextField", textField instanceof WindowsTextField); // 验证不是其他类型 assertFalse("按钮不应为MacOSButton", button instanceof MacOSButton); assertFalse("复选框不应为MacOSCheckbox", checkbox instanceof MacOSCheckbox); assertFalse("文本框不应为MacOSTextField", textField instanceof MacOSTextField); } @Test public void testMacOSFactoryCreatesMacOSProducts() { GUIFactory factory = new MacOSFactory(); Button button = factory.createButton(); Checkbox checkbox = factory.createCheckbox(); TextField textField = factory.createTextField(); // 验证产品类型 assertTrue("按钮应为MacOSButton", button instanceof MacOSButton); assertTrue("复选框应为MacOSCheckbox", checkbox instanceof MacOSCheckbox); assertTrue("文本框应为MacOSTextField", textField instanceof MacOSTextField); // 验证不是其他类型 assertFalse("按钮不应为WindowsButton", button instanceof WindowsButton); assertFalse("复选框不应为WindowsCheckbox", checkbox instanceof WindowsCheckbox); assertFalse("文本框不应为WindowsTextField", textField instanceof WindowsTextField); } @Test public void testApplicationWithWindowsFactory() { GUIFactory factory = new WindowsFactory(); Application app = new Application(factory); app.createUI(); assertNotNull("按钮不应为null", app.getButton()); assertNotNull("复选框不应为null", app.getCheckbox()); assertNotNull("文本框不应为null", app.getTextField()); assertTrue("工厂应为WindowsFactory", app.getFactory() instanceof WindowsFactory); } @Test public void testApplicationWithMacOSFactory() { GUIFactory factory = new MacOSFactory(); Application app = new Application(factory); app.createUI(); assertNotNull("按钮不应为null", app.getButton()); assertNotNull("复选框不应为null", app.getCheckbox()); assertNotNull("文本框不应为null", app.getTextField()); assertTrue("工厂应为MacOSFactory", app.getFactory() instanceof MacOSFactory); } @Test public void testWindowsButtonFunctionality() { WindowsButton button = new WindowsButton(); assertFalse("初始状态不应被点击", button.isClicked()); button.click(); assertTrue("点击后应被标记为已点击", button.isClicked()); // 验证渲染方法不会抛出异常 button.paint(); } @Test public void testMacOSCheckboxFunctionality() { MacOSCheckbox checkbox = new MacOSCheckbox(); assertFalse("初始状态应未选中", checkbox.isChecked()); checkbox.check(); assertTrue("第一次点击后应选中", checkbox.isChecked()); checkbox.check(); assertFalse("第二次点击后应取消选中", checkbox.isChecked()); // 验证渲染方法不会抛出异常 checkbox.paint(); } @Test public void testTextFieldTextOperations() { WindowsTextField textField = new WindowsTextField(); assertEquals("初始文本应为空", "", textField.getText()); textField.setText("测试文本"); assertEquals("设置后文本应匹配", "测试文本", textField.getText()); // 验证渲染方法不会抛出异常 textField.paint(); } }
3. 构建和运行
-
项目构建
在项目根目录下执行:
bash# 清理并编译项目 mvn clean compile # 运行测试 mvn test # 打包 mvn package # 运行程序 java -cp target/abstract-factory-demo-1.0-SNAPSHOT.jar com.example.abstractfactory.Main -
直接运行主类
bash# 编译并运行 mvn compile exec:java -Dexec.mainClass="com.example.abstractfactory.Main" -
运行测试
bashmvn test
4. 核心概念
模式组成
- AbstractFactory(抽象工厂):声明创建抽象产品的方法 - GUIFactory
- ConcreteFactory(具体工厂):实现创建具体产品的方法 - WindowsFactory, MacOSFactory
- AbstractProduct(抽象产品):为产品族声明接口 - Button, Checkbox, TextField
- ConcreteProduct(具体产品):实现抽象产品接口 - WindowsButton, MacOSButton等
- Client(客户端):使用抽象工厂和产品接口 - Application
抽象工厂 vs 工厂方法
| 特性 | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|
| 核心目的 | 创建一个产品 | 创建产品家族 |
| 工厂类型 | 一个工厂方法 | 多个工厂方法 |
| 产品关系 | 单一产品 | 相关产品族 |
| 扩展性 | 易于添加新产品 | 易于添加新家族 |
| 复杂度 | 相对简单 | 相对复杂 |
优点
- 产品兼容性:确保创建的对象属于同一家族
- 单一职责原则:产品创建代码集中在一处
- 开闭原则:引入新家族无需修改已有代码
- 解耦:客户端与具体产品类解耦
缺点
- 复杂度高:需要定义许多接口和类
- 扩展困难:添加新产品需要修改所有工厂
- 过度设计:对于简单场景可能过于复杂
应用场景
- 系统需要独立于其产品的创建、组合和表示
- 系统需要配置多个产品家族中的一个
- 需要强调一系列相关产品对象的设计以便联合使用
- 提供一个产品类库,只暴露接口而不暴露实现