创建型模式详解
创建型模式关注对象的创建过程,将对象的创建与使用分离,提供灵活的对象创建机制。本章将深入探讨五种创建型模式的原理、实现方式和实际应用。
核心价值
创建型模式 = 封装对象创建 + 灵活实例化 + 创建与使用分离
- 🔍 隐藏实现细节:屏蔽对象的实例化过程,使系统更专注于业务逻辑
- 🔄 提高可扩展性:在不修改客户端代码的情况下引入新的具体类型
- 🛠️ 增强代码复用:避免代码重复,提高代码质量和可维护性
- 🧩 降低系统耦合度:减少系统各部分的相互依赖
创建型模式概览
1. 单例模式(Singleton)
1.1 模式定义
单例模式确保一个类只有一个实例,并提供一个全局访问点。
- 适用场景
- 优点
- 缺点
- 资源共享:当需要共享昂贵的资源时(如数据库连接池)
- 全局状态管理:需要维护全局状态或配置时
- 协调操作:需要协调系统行为的场景(如日志记录器)
- 节省资源:避免重复创建对象,减少内存占用
- 全局访问点:提供统一的访问入口
- 协调行为:可以协调系统中的行为和资源
- 全局状态:可能造成全局状态难以调试和测试
- 单一职责违反:既要管理自身实例,又要完成业务逻辑
- 隐藏依赖:客户端与单例存在隐式依赖,不利于依赖注入
1.2 实现方式
饿汉式单例
饿汉式单例
java
1public class EagerSingleton {2 // 类加载时就初始化,线程安全3 private static final EagerSingleton instance = new EagerSingleton();4 5 // 私有构造函数6 private EagerSingleton() {7 // 防止反射攻击8 if (instance != null) {9 throw new RuntimeException("单例模式不允许创建多个实例");10 }11 }12 13 // 全局访问点14 public static EagerSingleton getInstance() {15 return instance;16 }17 18 // 业务方法19 public void doSomething() {20 System.out.println("饿汉式单例执行操作");21 }22}懒汉式单例
懒汉式单例
java
1public class LazySingleton {2 // 延迟初始化3 private static volatile LazySingleton instance;4 5 private LazySingleton() {}6 7 // 双重检查锁定(Double-Checked Locking)8 public static LazySingleton getInstance() {9 if (instance == null) {10 synchronized (LazySingleton.class) {11 if (instance == null) {12 instance = new LazySingleton();13 }14 }15 }16 return instance;17 }18 19 public void doSomething() {20 System.out.println("懒汉式单例执行操作");21 }22}静态内部类单例
静态内部类单例
java
1public class StaticInnerSingleton {2 private StaticInnerSingleton() {}3 4 // 静态内部类5 private static class SingletonHolder {6 private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();7 }8 9 public static StaticInnerSingleton getInstance() {10 return SingletonHolder.INSTANCE;11 }12 13 public void doSomething() {14 System.out.println("静态内部类单例执行操作");15 }16}枚举单例(推荐)
枚举单例
java
1public enum EnumSingleton {2 INSTANCE;3 4 public void doSomething() {5 System.out.println("枚举单例执行操作");6 }7 8 // 可以添加其他方法9 public void anotherMethod() {10 System.out.println("枚举单例的其他方法");11 }12}1.3 单例模式实现对比
| 实现方式 | 线程安全 | 延迟加载 | 序列化安全 | 防反射攻击 | JVM保证 | 推荐指数 |
|---|---|---|---|---|---|---|
| 饿汉式 | ✅ | ❌ | ❌ | ✅ | ✅ | ⭐⭐⭐ |
| 懒汉式 | ✅ | ✅ | ❌ | ❌ | ❌ | ⭐⭐ |
| 静态内部类 | ✅ | ✅ | ❌ | ❌ | ✅ | ⭐⭐⭐⭐ |
| 枚举方式 | ✅ | ❌ | ✅ | ✅ | ✅ | ⭐⭐⭐⭐⭐ |
1.4 应用场景
- 配置管理器
- 数据库连接池
- 日志记录器
配置管理器
java
1public class ConfigurationManager {2 private static volatile ConfigurationManager instance;3 private Properties properties;4 5 private ConfigurationManager() {6 loadConfiguration();7 }8 9 public static ConfigurationManager getInstance() {10 if (instance == null) {11 synchronized (ConfigurationManager.class) {12 if (instance == null) {13 instance = new ConfigurationManager();14 }15 }16 }17 return instance;18 }19 20 private void loadConfiguration() {21 properties = new Properties();22 try (InputStream input = getClass().getClassLoader()23 .getResourceAsStream("config.properties")) {24 properties.load(input);25 } catch (IOException e) {26 throw new RuntimeException("Failed to load configuration", e);27 }28 }29 30 public String getProperty(String key) {31 return properties.getProperty(key);32 }33}数据库连接池
java
1public class DatabaseConnectionPool {2 private static DatabaseConnectionPool instance;3 private final Queue<Connection> connectionPool;4 private final int maxConnections;5 6 private DatabaseConnectionPool(int maxConnections) {7 this.maxConnections = maxConnections;8 this.connectionPool = new LinkedList<>();9 initializePool();10 }11 12 public static synchronized DatabaseConnectionPool getInstance() {13 if (instance == null) {14 instance = new DatabaseConnectionPool(10);15 }16 return instance;17 }18 19 private void initializePool() {20 for (int i = 0; i < maxConnections; i++) {21 connectionPool.offer(createConnection());22 }23 }24 25 private Connection createConnection() {26 // 创建数据库连接的逻辑27 return null; // 简化示例28 }29 30 public Connection getConnection() {31 return connectionPool.poll();32 }33 34 public void releaseConnection(Connection connection) {35 if (connectionPool.size() < maxConnections) {36 connectionPool.offer(connection);37 }38 }39}日志记录器
java
1public class LoggerSingleton {2 private static final LoggerSingleton INSTANCE = new LoggerSingleton();3 private final BufferedWriter writer;4 5 private LoggerSingleton() {6 try {7 writer = new BufferedWriter(new FileWriter("application.log", true));8 } catch (IOException e) {9 throw new RuntimeException("无法初始化日志文件", e);10 }11 }12 13 public static LoggerSingleton getInstance() {14 return INSTANCE;15 }16 17 public void log(String message) {18 try {19 writer.write(LocalDateTime.now() + ": " + message);20 writer.newLine();21 writer.flush();22 } catch (IOException e) {23 System.err.println("日志写入失败: " + e.getMessage());24 }25 }26 27 // 确保资源释放28 @Override29 protected void finalize() throws Throwable {30 writer.close();31 super.finalize();32 }33}1.5 实现注意事项
多线程安全性
单例模式在多线程环境中实现时需要特别注意线程安全问题:
- 懒汉式需要使用双重检查锁定并加上
volatile关键字 - 饿汉式和枚举方式天生是线程安全的
- 避免使用没有同步措施的懒加载方式
最佳实践
- 推荐优先使用枚举实现单例,简洁且有JVM保证的线程和序列化安全
- 需要延迟加载时,使用静态内部类方式
- 考虑使用依赖注入框架来管理单例,而不是手动实现
2. 工厂方法模式(Factory Method)
2.1 模式定义
工厂方法模式定义了一个创建对象的接口,但由子类决定实例化的类是哪一个。工厂方法将类的实例化推迟到子类中进行。
- 适用场景
- 优点
- 缺点
- 创建逻辑复杂:当对象的创建逻辑较为复杂时
- 类型多变:当需要创建的对象类型可能在运行时变化时
- 依赖倒置:想依赖抽象而非具体类时
- 框架设计:框架需要为用户提供扩展点时
- 解耦:将产品的创建与使用解耦
- 单一职责:将创建逻辑集中到专门的工厂类
- 开闭原则:可以引入新的产品类而无需修改现有代码
- 可定制:子类可以改变工厂方法的返回类型
- 类爆炸:每添加一个产品就需要添加一个具体工厂类
- 复杂度:引入了额外的抽象层,增加了理解难度
- 继承约束:通常需要创建子类来使用工厂方法
2.2 实现方式
基本工厂方法模式
工厂方法模式
java
1// 抽象产品2public interface Product {3 void operation();4}56// 具体产品A7public class ConcreteProductA implements Product {8 @Override9 public void operation() {10 System.out.println("产品A的操作");11 }12}1314// 具体产品B15public class ConcreteProductB implements Product {16 @Override17 public void operation() {18 System.out.println("产品B的操作");19 }20}2122// 抽象工厂23public abstract class Creator {24 // 工厂方法25 public abstract Product createProduct();26 27 // 模板方法28 public void someOperation() {29 Product product = createProduct();30 product.operation();31 }32}3334// 具体工厂A35public class ConcreteCreatorA extends Creator {36 @Override37 public Product createProduct() {38 return new ConcreteProductA();39 }40}4142// 具体工厂B43public class ConcreteCreatorB extends Creator {44 @Override45 public Product createProduct() {46 return new ConcreteProductB();47 }48}参数化工厂方法
参数化工厂方法
java
1public abstract class Creator {2 public Product createProduct(String type) {3 Product product = createProductImpl(type);4 // 可以在这里添加通用的初始化逻辑5 return product;6 }7 8 protected abstract Product createProductImpl(String type);9}1011public class ConcreteCreator extends Creator {12 @Override13 protected Product createProductImpl(String type) {14 switch (type) {15 case "A":16 return new ConcreteProductA();17 case "B":18 return new ConcreteProductB();19 default:20 throw new IllegalArgumentException("Unknown product type: " + type);21 }22 }23}2.3 工厂方法模式变体
- 简单工厂
- 静态工厂方法
简单工厂(非GoF设计模式)
java
1public class SimpleFactory {2 public static Product createProduct(String type) {3 switch (type) {4 case "A":5 return new ConcreteProductA();6 case "B":7 return new ConcreteProductB();8 default:9 throw new IllegalArgumentException("Unknown product type: " + type);10 }11 }12}1314// 使用示例15public class Client {16 public void doSomething() {17 Product product = SimpleFactory.createProduct("A");18 product.operation();19 }20}简单工厂不属于GoF设计模式,但常作为工厂方法的简化版本使用。
静态工厂方法
java
1public class Product {2 private Product() { }3 4 public void operation() {5 System.out.println("产品操作");6 }7 8 // 静态工厂方法9 public static Product createProductA() {10 return new Product();11 }12 13 public static Product createProductWithName(String name) {14 Product product = new Product();15 // 设置产品名称16 return product;17 }18}1920// 使用示例21public class Client {22 public void doSomething() {23 Product product = Product.createProductA();24 product.operation();25 }26}静态工厂方法是面向对象编程中常见的实现技巧,通常在一个类中提供静态方法来创建对象。
2.4 工厂方法vs简单工厂
| 特性 | 工厂方法 | 简单工厂 |
|---|---|---|
| 类型 | GoF设计模式 | 编程习惯 |
| 创建方式 | 通过继承 | 通过条件判断 |
| 扩展方式 | 添加新的工厂子类 | 修改工厂类代码 |
| 开闭原则 | 符合 | 不完全符合 |
| 复杂度 | 较高 | 较低 |
| 灵活性 | 更灵活 | 较简单 |
| 适用场景 | 复杂对象创建、框架设计 | 简单对象创建、小型应用 |
2.5 应用场景
- 数据库连接
- 日志记录器
- UI元素创建
数据库连接工厂
java
1// 数据库连接接口2public interface DatabaseConnection {3 void connect();4 void disconnect();5}67// MySQL连接实现8public class MySQLConnection implements DatabaseConnection {9 @Override10 public void connect() {11 System.out.println("连接MySQL数据库");12 }13 14 @Override15 public void disconnect() {16 System.out.println("断开MySQL数据库连接");17 }18}1920// PostgreSQL连接实现21public class PostgreSQLConnection implements DatabaseConnection {22 @Override23 public void connect() {24 System.out.println("连接PostgreSQL数据库");25 }26 27 @Override28 public void disconnect() {29 System.out.println("断开PostgreSQL数据库连接");30 }31}3233// 数据库连接工厂接口34public abstract class DatabaseConnectionFactory {35 public abstract DatabaseConnection createConnection();36 37 public DatabaseConnection getConnection() {38 DatabaseConnection connection = createConnection();39 // 可以在这里添加连接池管理逻辑40 return connection;41 }42}4344// MySQL连接工厂45public class MySQLConnectionFactory extends DatabaseConnectionFactory {46 @Override47 public DatabaseConnection createConnection() {48 return new MySQLConnection();49 }50}5152// PostgreSQL连接工厂53public class PostgreSQLConnectionFactory extends DatabaseConnectionFactory {54 @Override55 public DatabaseConnection createConnection() {56 return new PostgreSQLConnection();57 }58}日志记录工厂
java
1// 日志接口2public interface Logger {3 void log(String message);4}56// 控制台日志7public class ConsoleLogger implements Logger {8 @Override9 public void log(String message) {10 System.out.println("控制台日志: " + message);11 }12}1314// 文件日志15public class FileLogger implements Logger {16 private String filePath;17 18 public FileLogger(String filePath) {19 this.filePath = filePath;20 }21 22 @Override23 public void log(String message) {24 System.out.println("写入文件日志: " + filePath + " - " + message);25 }26}2728// 日志工厂29public abstract class LoggerFactory {30 public abstract Logger createLogger();31}3233// 控制台日志工厂34public class ConsoleLoggerFactory extends LoggerFactory {35 @Override36 public Logger createLogger() {37 return new ConsoleLogger();38 }39}4041// 文件日志工厂42public class FileLoggerFactory extends LoggerFactory {43 private String filePath;44 45 public FileLoggerFactory(String filePath) {46 this.filePath = filePath;47 }48 49 @Override50 public Logger createLogger() {51 return new FileLogger(filePath);52 }53}UI元素工厂
java
1// UI元素接口2public interface UIElement {3 void render();4}56// 按钮元素7public class Button implements UIElement {8 @Override9 public void render() {10 System.out.println("渲染按钮");11 }12}1314// 文本框元素15public class TextField implements UIElement {16 @Override17 public void render() {18 System.out.println("渲染文本框");19 }20}2122// UI元素工厂23public abstract class UIElementFactory {24 public abstract UIElement createElement();25}2627// 按钮工厂28public class ButtonFactory extends UIElementFactory {29 @Override30 public UIElement createElement() {31 return new Button();32 }33}3435// 文本框工厂36public class TextFieldFactory extends UIElementFactory {37 @Override38 public UIElement createElement() {39 return new TextField();40 }41}工厂方法模式最佳实践
- 命名清晰:为工厂方法使用描述性名称,如
createXXX、newXXX、getXXX - 预初始化:可以在工厂方法中对创建的对象进行预初始化或验证
- 层次平衡:避免创建过深的工厂继承层次
- 单一职责:一个工厂类只负责创建一种类型的产品
- 参数控制:根据需要选择使用参数化工厂方法或专用工厂子类
3. 抽象工厂模式(Abstract Factory)
3.1 模式定义
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。它是工厂方法模式的扩展,用于创建产品族。
- 适用场景
- 优点
- 缺点
- 产品族创建:需要创建一系列相关产品时
- 一致性保证:需要确保创建的产品彼此兼容
- 平台独立:系统需要与多个平台或技术集成
- 隔离变化:隔离产品创建的具体细节
- 一致性:保证了一系列相关产品的兼容性
- 隔离具体类:客户端与具体产品解耦
- 易于切换:可以整体切换产品族
- 开闭原则:增加新的产品族不需要修改已有代码
- 难以扩展产品种类:添加新产品类型需要修改抽象工厂接口
- 复杂度:引入了大量的接口和类
- 产品族约束:所有产品必须同时被支持
3.2 实现示例
抽象工厂模式
java
1// 抽象产品A2public interface AbstractProductA {3 void operationA();4}56// 抽象产品B7public interface AbstractProductB {8 void operationB();9}1011// 具体产品A112public class ConcreteProductA1 implements AbstractProductA {13 @Override14 public void operationA() {15 System.out.println("产品A1的操作");16 }17}1819// 具体产品A220public class ConcreteProductA2 implements AbstractProductA {21 @Override22 public void operationA() {23 System.out.println("产品A2的操作");24 }25}2627// 具体产品B128public class ConcreteProductB1 implements AbstractProductB {29 @Override30 public void operationB() {31 System.out.println("产品B1的操作");32 }33}3435// 具体产品B236public class ConcreteProductB2 implements AbstractProductB {37 @Override38 public void operationB() {39 System.out.println("产品B2的操作");40 }41}4243// 抽象工厂44public interface AbstractFactory {45 AbstractProductA createProductA();46 AbstractProductB createProductB();47}4849// 具体工厂150public class ConcreteFactory1 implements AbstractFactory {51 @Override52 public AbstractProductA createProductA() {53 return new ConcreteProductA1();54 }55 56 @Override57 public AbstractProductB createProductB() {58 return new ConcreteProductB1();59 }60}6162// 具体工厂263public class ConcreteFactory2 implements AbstractFactory {64 @Override65 public AbstractProductA createProductA() {66 return new ConcreteProductA2();67 }68 69 @Override70 public AbstractProductB createProductB() {71 return new ConcreteProductB2();72 }73}3.3 抽象工厂与工厂方法对比
| 特性 | 抽象工厂 | 工厂方法 |
|---|---|---|
| 目的 | 创建产品族 | 创建单个产品 |
| 接口 | 多个创建方法 | 单个创建方法 |
| 扩展产品族 | 容易(增加工厂类) | 不适用 |
| 扩展产品种类 | 困难(修改接口) | 容易(增加产品类) |
| 抽象层次 | 更高 | 较低 |
| 复杂度 | 更复杂 | 较简单 |
| 适用场景 | 多系列产品集成 | 单一产品创建 |
3.4 应用场景
- UI组件
- 数据库连接
UI组件抽象工厂
java
1// 按钮接口2public interface Button {3 void render();4 void onClick();5}67// 复选框接口8public interface Checkbox {9 void render();10 boolean isChecked();11}1213// Windows风格按钮14public class WindowsButton implements Button {15 @Override16 public void render() {17 System.out.println("渲染Windows风格按钮");18}1920 @Override21 public void onClick() {22 System.out.println("Windows按钮点击事件");23 }24}2526// Windows风格复选框27public class WindowsCheckbox implements Checkbox {28 private boolean checked = false;29 30 @Override31 public void render() {32 System.out.println("渲染Windows风格复选框");33 }34 35 @Override36 public boolean isChecked() {37 return checked;38 }39}4041// macOS风格按钮42public class MacButton implements Button {43 @Override44 public void render() {45 System.out.println("渲染macOS风格按钮");46 }47 48 @Override49 public void onClick() {50 System.out.println("macOS按钮点击事件");51 }52}5354// macOS风格复选框55public class MacCheckbox implements Checkbox {56 private boolean checked = false;57 58 @Override59 public void render() {60 System.out.println("渲染macOS风格复选框");61 }62 63 @Override64 public boolean isChecked() {65 return checked;66 }67}6869// UI工厂接口70public interface UIFactory {71 Button createButton();72 Checkbox createCheckbox();73}7475// Windows UI工厂76public class WindowsUIFactory implements UIFactory {77 @Override78 public Button createButton() {79 return new WindowsButton();80 }81 82 @Override83 public Checkbox createCheckbox() {84 return new WindowsCheckbox();85 }86}8788// macOS UI工厂89public class MacUIFactory implements UIFactory {90 @Override91 public Button createButton() {92 return new MacButton();93 }94 95 @Override96 public Checkbox createCheckbox() {97 return new MacCheckbox();98 }99}100101// 客户端应用102public class Application {103 private Button button;104 private Checkbox checkbox;105 106 public Application(UIFactory factory) {107 button = factory.createButton();108 checkbox = factory.createCheckbox();109 }110 111 public void render() {112 button.render();113 checkbox.render();114 }115}116117// 根据操作系统选择工厂118public class ApplicationRunner {119 public static void main(String[] args) {120 UIFactory factory;121 String osName = System.getProperty("os.name").toLowerCase();122 123 if (osName.contains("windows")) {124 factory = new WindowsUIFactory();125 } else {126 factory = new MacUIFactory();127 }128 129 Application app = new Application(factory);130 app.render();131 }132}数据库抽象工厂
java
1// 数据库连接接口2public interface Connection {3 void open();4 void close();5 void executeQuery(String query);6}78// 事务接口9public interface Transaction {10 void begin();11 void commit();12 void rollback();13}1415// MySQL连接16public class MySQLConnection implements Connection {17 @Override18 public void open() {19 System.out.println("打开MySQL连接");20 }21 22 @Override23 public void close() {24 System.out.println("关闭MySQL连接");25 }26 27 @Override28 public void executeQuery(String query) {29 System.out.println("MySQL执行查询: " + query);30 }31}3233// MySQL事务34public class MySQLTransaction implements Transaction {35 @Override36 public void begin() {37 System.out.println("开始MySQL事务");38 }39 40 @Override41 public void commit() {42 System.out.println("提交MySQL事务");43 }44 45 @Override46 public void rollback() {47 System.out.println("回滚MySQL事务");48 }49}5051// PostgreSQL连接52public class PostgreSQLConnection implements Connection {53 @Override54 public void open() {55 System.out.println("打开PostgreSQL连接");56 }57 58 @Override59 public void close() {60 System.out.println("关闭PostgreSQL连接");61 }62 63 @Override64 public void executeQuery(String query) {65 System.out.println("PostgreSQL执行查询: " + query);66 }67}6869// PostgreSQL事务70public class PostgreSQLTransaction implements Transaction {71 @Override72 public void begin() {73 System.out.println("开始PostgreSQL事务");74 }75 76 @Override77 public void commit() {78 System.out.println("提交PostgreSQL事务");79 }80 81 @Override82 public void rollback() {83 System.out.println("回滚PostgreSQL事务");84 }85}8687// 数据库抽象工厂88public interface DatabaseFactory {89 Connection createConnection();90 Transaction createTransaction();91}9293// MySQL工厂94public class MySQLFactory implements DatabaseFactory {95 @Override96 public Connection createConnection() {97 return new MySQLConnection();98 }99 100 @Override101 public Transaction createTransaction() {102 return new MySQLTransaction();103 }104}105106// PostgreSQL工厂107public class PostgreSQLFactory implements DatabaseFactory {108 @Override109 public Connection createConnection() {110 return new PostgreSQLConnection();111 }112 113 @Override114 public Transaction createTransaction() {115 return new PostgreSQLTransaction();116 }117}3.5 抽象工厂模式的变体
带有工厂方法的抽象工厂
带有工厂方法的抽象工厂
java
1public abstract class AbstractFactory {2 public abstract Button createButton();3 public abstract Checkbox createCheckbox();4 5 // 静态工厂方法6 public static AbstractFactory getFactory(String type) {7 if ("windows".equalsIgnoreCase(type)) {8 return new WindowsUIFactory();9 } else if ("mac".equalsIgnoreCase(type)) {10 return new MacUIFactory();11 } else {12 throw new IllegalArgumentException("Unknown UI type: " + type);13 }14 }15}使用反射的抽象工厂
使用反射的抽象工厂
java
1public class ReflectiveFactory implements AbstractFactory {2 private Class<?> buttonClass;3 private Class<?> checkboxClass;4 5 public ReflectiveFactory(String buttonClassName, String checkboxClassName) 6 throws ClassNotFoundException {7 this.buttonClass = Class.forName(buttonClassName);8 this.checkboxClass = Class.forName(checkboxClassName);9 }10 11 @Override12 public Button createButton() {13 try {14 return (Button) buttonClass.newInstance();15 } catch (Exception e) {16 throw new RuntimeException("Cannot create button", e);17 }18 }19 20 @Override21 public Checkbox createCheckbox() {22 try {23 return (Checkbox) checkboxClass.newInstance();24 } catch (Exception e) {25 throw new RuntimeException("Cannot create checkbox", e);26 }27 }28}抽象工厂最佳实践
- 产品族划分:按照产品之间的关联性和一致性进行合理划分
- 接口设计:设计清晰、内聚的接口,避免过于臃肿的抽象工厂接口
- 工厂扩展:考虑使用工厂方法或简单工厂来创建抽象工厂实例
- 产品扩展:预留产品种类扩展的机制,例如使用默认实现或可选方法
- 配置驱动:考虑使用配置文件或反射机制来动态选择工厂实现
4. 建造者模式(Builder)
4.1 模式定义
建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。它允许我们分步骤创建复杂对象,并能轻松控制创建过程。
- 适用场景
- 优点
- 缺点
- 复杂对象创建:对象具有复杂的内部结构或多个组成部分
- 不同表示:同一个对象在不同场景下有不同的表示形式
- 分步构建:需要对象的创建过程可控且灵活
- 参数校验:需要在对象创建时进行复杂的参数校验
- 分步创建:将复杂对象的创建过程分解为多个步骤
- 链式调用:支持流式接口,提高可读性
- 封装细节:隐藏产品的内部结构和组装细节
- 代码复用:相同的构建过程可以创建不同的产品表示
- 代码量增加:需要创建多个新的类
- 特定场景:仅适用于对象相对复杂且创建过程稳定的情况
- 耦合风险:具体建造者可能与产品类存在较强的耦合
4.2 实现方式
基本建造者模式
建造者模式
java
1// 产品类2public class Computer {3 private String cpu;4 private String memory;5 private String storage;6 private String graphics;7 private String motherboard;8 9 // 私有构造函数10 private Computer() {}11 12 // Getter方法13 public String getCpu() { return cpu; }14 public String getMemory() { return memory; }15 public String getStorage() { return storage; }16 public String getGraphics() { return graphics; }17 public String getMotherboard() { return motherboard; }18 19 @Override20 public String toString() {21 return String.format("Computer{cpu='%s', memory='%s', storage='%s', graphics='%s', motherboard='%s'}", 22 cpu, memory, storage, graphics, motherboard);23 }24 25 // 静态内部建造者类26 public static class Builder {27 private Computer computer = new Computer();28 29 public Builder cpu(String cpu) {30 computer.cpu = cpu;31 return this;32 }33 34 public Builder memory(String memory) {35 computer.memory = memory;36 return this;37 }38 39 public Builder storage(String storage) {40 computer.storage = storage;41 return this;42 }43 44 public Builder graphics(String graphics) {45 computer.graphics = graphics;46 return this;47 }48 49 public Builder motherboard(String motherboard) {50 computer.motherboard = motherboard;51 return this;52 }53 54 public Computer build() {55 // 参数校验56 validate();57 return computer;58 }59 60 private void validate() {61 if (computer.cpu == null) {62 throw new IllegalArgumentException("CPU不能为空");63 }64 if (computer.memory == null) {65 throw new IllegalArgumentException("内存不能为空");66 }67 if (computer.storage == null) {68 throw new IllegalArgumentException("存储不能为空");69 }70 }71 }72}使用指导者的建造者模式
带指导者的建造者模式
java
1// 产品类2public class House {3 private String foundation;4 private String structure;5 private String roof;6 private String interior;7 8 public void setFoundation(String foundation) {9 this.foundation = foundation;10 }11 12 public void setStructure(String structure) {13 this.structure = structure;14 }15 16 public void setRoof(String roof) {17 this.roof = roof;18 }19 20 public void setInterior(String interior) {21 this.interior = interior;22 }23 24 @Override25 public String toString() {26 return String.format("House{foundation='%s', structure='%s', roof='%s', interior='%s'}", 27 foundation, structure, roof, interior);28 }29}3031// 抽象建造者32public interface HouseBuilder {33 void buildFoundation();34 void buildStructure();35 void buildRoof();36 void buildInterior();37 House getResult();38}3940// 具体建造者 - 砖房41public class BrickHouseBuilder implements HouseBuilder {42 private House house = new House();43 44 @Override45 public void buildFoundation() {46 house.setFoundation("混凝土地基");47 }48 49 @Override50 public void buildStructure() {51 house.setStructure("砖墙结构");52 }53 54 @Override55 public void buildRoof() {56 house.setRoof("平屋顶");57 }58 59 @Override60 public void buildInterior() {61 house.setInterior("标准内部装修");62 }63 64 @Override65 public House getResult() {66 return house;67 }68}6970// 具体建造者 - 木房71public class WoodenHouseBuilder implements HouseBuilder {72 private House house = new House();73 74 @Override75 public void buildFoundation() {76 house.setFoundation("条形地基");77 }78 79 @Override80 public void buildStructure() {81 house.setStructure("木质框架结构");82 }83 84 @Override85 public void buildRoof() {86 house.setRoof("坡屋顶");87 }88 89 @Override90 public void buildInterior() {91 house.setInterior("木质内部装修");92 }93 94 @Override95 public House getResult() {96 return house;97 }98}99100// 指导者101public class HouseDirector {102 private HouseBuilder builder;103 104 public HouseDirector(HouseBuilder builder) {105 this.builder = builder;106 }107 108 public void changeBuilder(HouseBuilder builder) {109 this.builder = builder;110 }111 112 // 构建完整的房子113 public House buildFullFeaturedHouse() {114 builder.buildFoundation();115 builder.buildStructure();116 builder.buildRoof();117 builder.buildInterior();118 return builder.getResult();119 }120 121 // 构建简易的房子122 public House buildMinimalHouse() {123 builder.buildFoundation();124 builder.buildStructure();125 builder.buildRoof();126 return builder.getResult();127 }128}129130// 客户端代码131public class BuilderPatternDemo {132 public static void main(String[] args) {133 HouseBuilder brickBuilder = new BrickHouseBuilder();134 HouseBuilder woodenBuilder = new WoodenHouseBuilder();135 136 HouseDirector director = new HouseDirector(brickBuilder);137 138 // 构建砖房139 House brickHouse = director.buildFullFeaturedHouse();140 System.out.println("砖房: " + brickHouse);141 142 // 切换建造者,构建木房143 director.changeBuilder(woodenBuilder);144 House woodenHouse = director.buildMinimalHouse();145 System.out.println("简易木房: " + woodenHouse);146 }147}4.3 建造者模式变体
流式建造者模式(链式调用)
流式建造者
java
1// 使用示例2public class BuilderExample {3 public static void main(String[] args) {4 // 构建高性能电脑5 Computer gamingComputer = new Computer.Builder()6 .cpu("Intel i9-12900K")7 .memory("32GB DDR5")8 .storage("2TB NVMe SSD")9 .graphics("RTX 4090")10 .motherboard("Z690")11 .build();12 13 System.out.println("游戏电脑: " + gamingComputer);14 15 // 构建办公电脑16 Computer officeComputer = new Computer.Builder()17 .cpu("Intel i5-12400")18 .memory("16GB DDR4")19 .storage("512GB SSD")20 .graphics("集成显卡")21 .motherboard("B660")22 .build();23 24 System.out.println("办公电脑: " + officeComputer);25 }26}步进式建造者模式
步进式建造者
java
1public class StepBuilder {2 // 步进接口3 public interface CpuStep {4 MemoryStep cpu(String cpu);5 }6 7 public interface MemoryStep {8 StorageStep memory(String memory);9 }10 11 public interface StorageStep {12 OptionalStep storage(String storage);13 }14 15 public interface OptionalStep {16 OptionalStep graphics(String graphics);17 OptionalStep motherboard(String motherboard);18 Computer build();19 }20 21 // 实现类22 public static class ComputerBuilder implements CpuStep, MemoryStep, StorageStep, OptionalStep {23 private Computer computer = new Computer();24 25 private ComputerBuilder() {}26 27 public static CpuStep newBuilder() {28 return new ComputerBuilder();29 }30 31 @Override32 public MemoryStep cpu(String cpu) {33 computer.setCpu(cpu);34 return this;35 }36 37 @Override38 public StorageStep memory(String memory) {39 computer.setMemory(memory);40 return this;41 }42 43 @Override44 public OptionalStep storage(String storage) {45 computer.setStorage(storage);46 return this;47 }48 49 @Override50 public OptionalStep graphics(String graphics) {51 computer.setGraphics(graphics);52 return this;53 }54 55 @Override56 public OptionalStep motherboard(String motherboard) {57 computer.setMotherboard(motherboard);58 return this;59 }60 61 @Override62 public Computer build() {63 return computer;64 }65 }66}6768// 使用步进式建造者69Computer computer = StepBuilder.ComputerBuilder.newBuilder()70 .cpu("Intel i7") // 必须的71 .memory("16GB DDR4") // 必须的72 .storage("1TB SSD") // 必须的73 .graphics("RTX 3080") // 可选的74 .build();4.4 应用场景
- 数据库配置构建器
- HTTP客户端构建器
- 文档构建器
数据库配置建造者
java
1public class DatabaseConfig {2 private String host;3 private int port;4 private String database;5 private String username;6 private String password;7 private int maxConnections;8 private int timeout;9 10 private DatabaseConfig() {}11 12 // Getter方法...13 14 public static class Builder {15 private DatabaseConfig config = new DatabaseConfig();16 17 public Builder host(String host) {18 config.host = host;19 return this;20 }21 22 public Builder port(int port) {23 config.port = port;24 return this;25 }26 27 public Builder database(String database) {28 config.database = database;29 return this;30 }31 32 public Builder username(String username) {33 config.username = username;34 return this;35 }36 37 public Builder password(String password) {38 config.password = password;39 return this;40 }41 42 public Builder maxConnections(int maxConnections) {43 config.maxConnections = maxConnections;44 return this;45 }46 47 public Builder timeout(int timeout) {48 config.timeout = timeout;49 return this;50 }51 52 public DatabaseConfig build() {53 // 设置默认值54 if (config.port == 0) {55 config.port = 3306;56 }57 if (config.maxConnections == 0) {58 config.maxConnections = 10;59 }60 if (config.timeout == 0) {61 config.timeout = 30;62 }63 64 validate();65 return config;66 }67 68 private void validate() {69 if (config.host == null || config.host.trim().isEmpty()) {70 throw new IllegalArgumentException("主机地址不能为空");71 }72 if (config.database == null || config.database.trim().isEmpty()) {73 throw new IllegalArgumentException("数据库名不能为空");74 }75 if (config.username == null || config.username.trim().isEmpty()) {76 throw new IllegalArgumentException("用户名不能为空");77 }78 }79 }80}8182// 使用示例83DatabaseConfig config = new DatabaseConfig.Builder()84 .host("localhost")85 .port(3306)86 .database("mydb")87 .username("user")88 .password("pass")89 .maxConnections(20)90 .build();HTTP客户端构建器
java
1public class HttpClient {2 private String baseUrl;3 private int connectionTimeout;4 private int readTimeout;5 private Map<String, String> headers;6 private String authToken;7 private boolean followRedirects;8 private int maxRetries;9 10 private HttpClient() {11 this.headers = new HashMap<>();12 }13 14 // 静态内部建造者类15 public static class Builder {16 private HttpClient client = new HttpClient();17 18 public Builder baseUrl(String baseUrl) {19 client.baseUrl = baseUrl;20 return this;21 }22 23 public Builder connectionTimeout(int connectionTimeout) {24 client.connectionTimeout = connectionTimeout;25 return this;26 }27 28 public Builder readTimeout(int readTimeout) {29 client.readTimeout = readTimeout;30 return this;31 }32 33 public Builder header(String key, String value) {34 client.headers.put(key, value);35 return this;36 }37 38 public Builder authToken(String authToken) {39 client.authToken = authToken;40 return this;41 }42 43 public Builder followRedirects(boolean followRedirects) {44 client.followRedirects = followRedirects;45 return this;46 }47 48 public Builder maxRetries(int maxRetries) {49 client.maxRetries = maxRetries;50 return this;51 }52 53 public HttpClient build() {54 // 设置默认值55 if (client.connectionTimeout == 0) {56 client.connectionTimeout = 5000;57 }58 if (client.readTimeout == 0) {59 client.readTimeout = 10000;60 }61 62 // 验证必要参数63 validate();64 65 return client;66 }67 68 private void validate() {69 if (client.baseUrl == null || client.baseUrl.trim().isEmpty()) {70 throw new IllegalArgumentException("基础URL不能为空");71 }72 }73 }74 75 public void execute(String path, String method) {76 System.out.println("执行HTTP请求:" + method + " " + baseUrl + path);77 System.out.println("连接超时:" + connectionTimeout + "ms,读取超时:" + readTimeout + "ms");78 System.out.println("头部信息:" + headers);79 if (authToken != null) {80 System.out.println("授权令牌:" + authToken);81 }82 }83}8485// 使用示例86HttpClient client = new HttpClient.Builder()87 .baseUrl("https://api.example.com")88 .connectionTimeout(3000)89 .readTimeout(5000)90 .header("Content-Type", "application/json")91 .header("Accept", "application/json")92 .authToken("my-auth-token")93 .followRedirects(true)94 .maxRetries(3)95 .build();9697client.execute("/users", "GET");文档构建器
java
1public class Document {2 private String title;3 private String header;4 private String content;5 private String footer;6 private List<String> sections;7 private String author;8 private LocalDate creationDate;9 10 private Document() {11 this.sections = new ArrayList<>();12 this.creationDate = LocalDate.now();13 }14 15 // Getter方法...16 17 public static class Builder {18 private Document document = new Document();19 20 public Builder title(String title) {21 document.title = title;22 return this;23 }24 25 public Builder header(String header) {26 document.header = header;27 return this;28 }29 30 public Builder content(String content) {31 document.content = content;32 return this;33 }34 35 public Builder footer(String footer) {36 document.footer = footer;37 return this;38 }39 40 public Builder addSection(String section) {41 document.sections.add(section);42 return this;43 }44 45 public Builder author(String author) {46 document.author = author;47 return this;48 }49 50 public Builder creationDate(LocalDate creationDate) {51 document.creationDate = creationDate;52 return this;53 }54 55 public Document build() {56 validate();57 return document;58 }59 60 private void validate() {61 if (document.title == null || document.title.trim().isEmpty()) {62 throw new IllegalArgumentException("文档标题不能为空");63 }64 if (document.content == null || document.content.trim().isEmpty()) {65 throw new IllegalArgumentException("文档内容不能为空");66 }67 }68 }69}7071// 使用示例72Document report = new Document.Builder()73 .title("季度销售报告")74 .header("2023年第三季度")75 .content("销售额达到1000万元...")76 .addSection("销售分析")77 .addSection("市场趋势")78 .addSection("未来展望")79 .footer("报告结束")80 .author("张三")81 .build();4.5 建造者模式与其他模式的对比
| 特性 | 建造者模式 | 工厂方法 | 抽象工厂 |
|---|---|---|---|
| 目的 | 分步创建复杂对象 | 创建单个产品 | 创建产品族 |
| 关注点 | 创建过程和步骤 | 产品类型 | 产品族和兼容性 |
| 可控性 | 高(分步构建) | 低(一次创建) | 中(关联创建) |
| 复杂度 | 中等 | 较低 | 高 |
| 链式API | 支持 | 通常不支持 | 通常不支持 |
| 参数校验 | 集中处理 | 分散处理 | 分散处理 |
建造者模式最佳实践
- 适当的封装:使用私有构造函数强制通过建造者创建对象
- 参数校验:在
build()方法中集中进行参数验证 - 默认值处理:为非必须参数提供合理的默认值
- 方法命名:使用描述性的方法名,使构建过程更易读
- 建造者内置:考虑将建造者类设计为产品类的内部类
- 流式接口:支持方法链(链式调用)以提高代码可读性
5. 原型模式(Prototype)
5.1 模式定义
原型模式通过复制现有对象来创建新对象,而不是通过实例化类。当创建对象的成本较高,且对象之间存在相似性时,使用原型模式可以提高性能并简化对象创建过程。
- 适用场景
- 优点
- 缺点
- 创建成本高:当对象创建过程复杂或代价高昂时
- 避免继承:当系统应该独立于产品创建、组合和表示时
- 动态配置:运行时需要动态添加和移除产品时
- 避免重复初始化:需要创建与现有对象相似的对象时
- 性能优化:避免了重复的初始化过程
- 动态创建:在运行时指定创建的对象
- 对象复制:复制对象而不依赖具体类
- 创建预配置对象:可以创建预配置的对象模板
- 深拷贝复杂:包含循环引用或复杂对象的深拷贝实现困难
- 构造函数限制:克隆过程绕过了构造函数
- 状态一致性:难以维护对象间的关联和状态一致性
5.2 实现方式
基本原型模式
原型模式
java
1// 原型接口2public interface Prototype extends Cloneable {3 Prototype clone();4 void display();5}67// 具体原型8public class ConcretePrototype implements Prototype {9 private String name;10 private List<String> attributes = new ArrayList<>();11 12 public ConcretePrototype(String name) {13 this.name = name;14 this.attributes.add("属性1");15 this.attributes.add("属性2");16 }17 18 @Override19 public Prototype clone() {20 try {21 ConcretePrototype clone = (ConcretePrototype) super.clone();22 // 深拷贝23 clone.attributes = new ArrayList<>(this.attributes);24 return clone;25 } catch (CloneNotSupportedException e) {26 throw new RuntimeException(e);27 }28 }29 30 @Override31 public void display() {32 System.out.println("原型名称: " + name);33 System.out.println("属性: " + attributes);34 }35 36 public void addAttribute(String attribute) {37 this.attributes.add(attribute);38 }39 40 public void setName(String name) {41 this.name = name;42 }43}原型管理器
原型管理器
java
1public class PrototypeManager {2 private Map<String, Prototype> prototypes = new HashMap<>();3 4 public void addPrototype(String key, Prototype prototype) {5 prototypes.put(key, prototype);6 }7 8 public Prototype getPrototype(String key) {9 Prototype prototype = prototypes.get(key);10 if (prototype != null) {11 return prototype.clone();12 }13 return null;14 }15 16 public void removePrototype(String key) {17 prototypes.remove(key);18 }19}2021// 使用示例22public class PrototypeExample {23 public static void main(String[] args) {24 PrototypeManager manager = new PrototypeManager();25 26 // 添加原型27 ConcretePrototype prototype1 = new ConcretePrototype("原型1");28 manager.addPrototype("type1", prototype1);29 30 // 克隆原型31 Prototype clone1 = manager.getPrototype("type1");32 Prototype clone2 = manager.getPrototype("type1");33 34 // 修改克隆对象35 if (clone1 instanceof ConcretePrototype) {36 ((ConcretePrototype) clone1).setName("克隆1");37 ((ConcretePrototype) clone1).addAttribute("新属性");38 }39 40 // 显示结果41 prototype1.display();42 clone1.display();43 clone2.display();44 }45}5.3 深拷贝与浅拷贝
- 浅拷贝
- 深拷贝
- 序列化实现深拷贝
浅拷贝实现
java
1public class ShallowCopy implements Cloneable {2 private String name;3 private List<String> items;4 5 public ShallowCopy(String name) {6 this.name = name;7 this.items = new ArrayList<>();8 }9 10 public void addItem(String item) {11 items.add(item);12 }13 14 @Override15 public ShallowCopy clone() {16 try {17 // 浅拷贝:引用类型成员变量共享引用18 return (ShallowCopy) super.clone();19 } catch (CloneNotSupportedException e) {20 throw new RuntimeException(e);21 }22 }23 24 @Override25 public String toString() {26 return "ShallowCopy{name='" + name + "', items=" + items + "}";27 }28 29 // Getter和Setter方法30 public String getName() { return name; }31 public void setName(String name) { this.name = name; }32 public List<String> getItems() { return items; }33}3435// 使用示例36ShallowCopy original = new ShallowCopy("原始对象");37original.addItem("条目1");38original.addItem("条目2");3940ShallowCopy clone = original.clone();41clone.setName("克隆对象");42clone.getItems().add("条目3"); // 修改克隆对象的列表4344System.out.println("原始对象: " + original); // 输出也包含"条目3"45System.out.println("克隆对象: " + clone);深拷贝实现
java
1public class DeepCopy implements Cloneable {2 private String name;3 private List<String> items;4 5 public DeepCopy(String name) {6 this.name = name;7 this.items = new ArrayList<>();8 }9 10 public void addItem(String item) {11 items.add(item);12 }13 14 @Override15 public DeepCopy clone() {16 try {17 DeepCopy clone = (DeepCopy) super.clone();18 // 深拷贝:创建引用类型成员变量的新实例19 clone.items = new ArrayList<>(this.items);20 return clone;21 } catch (CloneNotSupportedException e) {22 throw new RuntimeException(e);23 }24 }25 26 @Override27 public String toString() {28 return "DeepCopy{name='" + name + "', items=" + items + "}";29 }30 31 // Getter和Setter方法32 public String getName() { return name; }33 public void setName(String name) { this.name = name; }34 public List<String> getItems() { return items; }35}3637// 使用示例38DeepCopy original = new DeepCopy("原始对象");39original.addItem("条目1");40original.addItem("条目2");4142DeepCopy clone = original.clone();43clone.setName("克隆对象");44clone.getItems().add("条目3"); // 修改克隆对象的列表4546System.out.println("原始对象: " + original); // 不包含"条目3"47System.out.println("克隆对象: " + clone);通过序列化实现深拷贝
java
1public class SerializableDeepCopy implements Serializable {2 private static final long serialVersionUID = 1L;3 4 private String name;5 private List<String> items;6 7 public SerializableDeepCopy(String name) {8 this.name = name;9 this.items = new ArrayList<>();10 }11 12 public void addItem(String item) {13 items.add(item);14 }15 16 // 通过序列化实现深拷贝17 public SerializableDeepCopy deepCopy() {18 try {19 ByteArrayOutputStream bos = new ByteArrayOutputStream();20 ObjectOutputStream oos = new ObjectOutputStream(bos);21 oos.writeObject(this);22 23 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());24 ObjectInputStream ois = new ObjectInputStream(bis);25 return (SerializableDeepCopy) ois.readObject();26 } catch (Exception e) {27 throw new RuntimeException(e);28 }29 }30 31 @Override32 public String toString() {33 return "SerializableDeepCopy{name='" + name + "', items=" + items + "}";34 }35 36 // Getter和Setter方法37 public String getName() { return name; }38 public void setName(String name) { this.name = name; }39 public List<String> getItems() { return items; }40}5.4 应用场景
- 文档模板系统
- 配置复制
- 图形编辑器
文档模板系统
java
1public abstract class Document implements Cloneable {2 protected String title;3 protected String content;4 protected List<String> sections = new ArrayList<>();5 6 public abstract void display();7 8 @Override9 public Document clone() {10 try {11 Document clone = (Document) super.clone();12 // 深拷贝13 clone.sections = new ArrayList<>(this.sections);14 return clone;15 } catch (CloneNotSupportedException e) {16 throw new RuntimeException(e);17 }18 }19 20 public void setTitle(String title) {21 this.title = title;22 }23 24 public void setContent(String content) {25 this.content = content;26 }27 28 public void addSection(String section) {29 this.sections.add(section);30 }31}3233public class ReportDocument extends Document {34 @Override35 public void display() {36 System.out.println("报告文档: " + title);37 System.out.println("内容: " + content);38 System.out.println("章节: " + sections);39 }40}4142public class ProposalDocument extends Document {43 @Override44 public void display() {45 System.out.println("提案文档: " + title);46 System.out.println("内容: " + content);47 System.out.println("章节: " + sections);48 }49}5051// 文档模板管理器52public class DocumentTemplateManager {53 private Map<String, Document> templates = new HashMap<>();54 55 public void addTemplate(String name, Document template) {56 templates.put(name, template);57 }58 59 public Document createDocument(String templateName) {60 Document template = templates.get(templateName);61 if (template != null) {62 return template.clone();63 }64 return null;65 }66}配置复制系统
java
1public class AppConfig implements Cloneable {2 private Map<String, Object> settings = new HashMap<>();3 private List<String> features = new ArrayList<>();4 5 // 初始化默认配置6 public AppConfig() {7 settings.put("timeout", 3000);8 settings.put("maxConnections", 100);9 settings.put("cacheEnabled", true);10 11 features.add("basic");12 }13 14 public void addSetting(String key, Object value) {15 settings.put(key, value);16 }17 18 public Object getSetting(String key) {19 return settings.get(key);20 }21 22 public void enableFeature(String feature) {23 features.add(feature);24 }25 26 @Override27 public AppConfig clone() {28 try {29 AppConfig clone = (AppConfig) super.clone();30 // 深拷贝31 clone.settings = new HashMap<>(this.settings);32 clone.features = new ArrayList<>(this.features);33 return clone;34 } catch (CloneNotSupportedException e) {35 throw new RuntimeException(e);36 }37 }38 39 @Override40 public String toString() {41 return "AppConfig{settings=" + settings + ", features=" + features + "}";42 }43}4445// 使用示例46public class ConfigExample {47 public static void main(String[] args) {48 // 创建基本配置49 AppConfig baseConfig = new AppConfig();50 51 // 创建开发环境配置52 AppConfig devConfig = baseConfig.clone();53 devConfig.addSetting("debugEnabled", true);54 devConfig.enableFeature("development");55 56 // 创建生产环境配置57 AppConfig prodConfig = baseConfig.clone();58 prodConfig.addSetting("debugEnabled", false);59 prodConfig.addSetting("timeout", 1000);60 prodConfig.enableFeature("monitoring");61 62 System.out.println("开发环境配置: " + devConfig);63 System.out.println("生产环境配置: " + prodConfig);64 }65}图形编辑器
java
1public abstract class Shape implements Cloneable {2 private int x;3 private int y;4 private String color;5 6 public Shape(int x, int y, String color) {7 this.x = x;8 this.y = y;9 this.color = color;10 }11 12 public abstract void draw();13 14 @Override15 public Shape clone() {16 try {17 return (Shape) super.clone();18 } catch (CloneNotSupportedException e) {19 throw new RuntimeException(e);20 }21 }22 23 // Getter和Setter方法24 public int getX() { return x; }25 public void setX(int x) { this.x = x; }26 public int getY() { return y; }27 public void setY(int y) { this.y = y; }28 public String getColor() { return color; }29 public void setColor(String color) { this.color = color; }30}3132public class Circle extends Shape {33 private int radius;34 35 public Circle(int x, int y, String color, int radius) {36 super(x, y, color);37 this.radius = radius;38 }39 40 @Override41 public void draw() {42 System.out.println("绘制圆形: 坐标(" + getX() + "," + getY() + 43 "), 颜色=" + getColor() + ", 半径=" + radius);44 }45 46 public int getRadius() { return radius; }47 public void setRadius(int radius) { this.radius = radius; }48}4950public class Rectangle extends Shape {51 private int width;52 private int height;53 54 public Rectangle(int x, int y, String color, int width, int height) {55 super(x, y, color);56 this.width = width;57 this.height = height;58 }59 60 @Override61 public void draw() {62 System.out.println("绘制矩形: 坐标(" + getX() + "," + getY() + 63 "), 颜色=" + getColor() + 64 ", 宽=" + width + ", 高=" + height);65 }66 67 public int getWidth() { return width; }68 public void setWidth(int width) { this.width = width; }69 public int getHeight() { return height; }70 public void setHeight(int height) { this.height = height; }71}7273// 图形编辑器74public class GraphicEditor {75 private Map<String, Shape> shapeTemplates = new HashMap<>();76 77 public GraphicEditor() {78 // 初始化形状模板79 shapeTemplates.put("circle", new Circle(0, 0, "red", 10));80 shapeTemplates.put("rectangle", new Rectangle(0, 0, "blue", 20, 10));81 }82 83 public Shape createShape(String type) {84 Shape template = shapeTemplates.get(type);85 if (template != null) {86 return template.clone();87 }88 return null;89 }90}5.5 原型模式与其他模式对比
| 特性 | 原型模式 | 工厂方法 | 建造者模式 |
|---|---|---|---|
| 创建机制 | 克隆现有对象 | 创建新对象 | 分步构建对象 |
| 复杂度 | 低(直接复制) | 中等 | 高(多步骤) |
| 使用时机 | 避免重复初始化 | 封装创建逻辑 | 复杂对象构建 |
| 实现方法 | 实现clone()方法 | 子类化创建者 | 构建器或指导者 |
| 优势 | 性能好,避免初始化 | 扩展性好 | 灵活性高,参数控制 |
| 劣势 | 深拷贝复杂 | 类爆炸 | 代码量增加 |
原型模式最佳实践
- 优先使用深拷贝:确保对象及其内部对象都被正确克隆
- 处理特殊引用:注意处理循环引用和不可克隆的对象
- 使用序列化:对于复杂对象,可以使用序列化实现深拷贝
- 避免副作用:确保克隆操作不会对原对象产生副作用
- 模板注册中心:使用原型管理器注册和管理原型对象
6. 创建型模式对比
6.1 模式选择指南
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 单例模式 | 全局唯一实例 | 节省内存,全局访问 | 可能成为全局状态 |
| 工厂方法 | 延迟实例化,扩展产品 | 符合开闭原则 | 增加类的数量 |
| 抽象工厂 | 产品族创建 | 保证产品兼容性 | 扩展新产品族困难 |
| 建造者 | 复杂对象构建 | 参数校验,链式调用 | 增加代码复杂度 |
| 原型 | 对象克隆 | 避免重复初始化 | 深拷贝开销 |
6.2 性能考虑
创建型模式在性能上各有优劣,选择合适的模式需要考虑应用场景和性能需求:
性能对比示例
java
1// 单例模式 - 内存占用最小2public class SingletonExample {3 private static SingletonExample instance;4 5 public static SingletonExample getInstance() {6 if (instance == null) {7 instance = new SingletonExample();8 }9 return instance;10 }11}1213// 工厂模式 - 对象创建开销14public class FactoryExample {15 public Product createProduct(String type) {16 // 每次调用都可能创建新对象17 switch (type) {18 case "A": return new ProductA();19 case "B": return new ProductB();20 default: throw new IllegalArgumentException();21 }22 }23}2425// 原型模式 - 克隆开销26public class PrototypeExample implements Cloneable {27 private List<String> data = new ArrayList<>();28 29 @Override30 public PrototypeExample clone() {31 try {32 PrototypeExample clone = (PrototypeExample) super.clone();33 // 深拷贝开销34 clone.data = new ArrayList<>(this.data);35 return clone;36 } catch (CloneNotSupportedException e) {37 throw new RuntimeException(e);38 }39 }40}- 内存使用
- CPU使用
- 代码复杂度
| 模式 | 内存使用 | 描述 |
|---|---|---|
| 单例 | ⭐⭐⭐⭐⭐ | 最优(只有一个实例) |
| 工厂方法 | ⭐⭐⭐ | 中等(每次创建新对象) |
| 抽象工厂 | ⭐⭐⭐ | 中等(每个产品族创建多个对象) |
| 建造者 | ⭐⭐ | 较高(中间状态占用内存) |
| 原型 | ⭐⭐⭐⭐ | 良好(复用现有对象结构) |
| 模式 | CPU使用 | 描述 |
|---|---|---|
| 单例 | ⭐⭐⭐⭐⭐ | 最优(仅初始化一次) |
| 工厂方法 | ⭐⭐⭐ | 中等(每次创建需初始化) |
| 抽象工厂 | ⭐⭐⭐ | 中等(创建多个相关对象) |
| 建造者 | ⭐⭐ | 较高(多步骤创建) |
| 原型 | ⭐⭐⭐⭐ | 良好(避免重复初始化) |
| 模式 | 代码复杂度 | 描述 |
|---|---|---|
| 单例 | ⭐⭐⭐⭐⭐ | 最简单(实现简洁) |
| 工厂方法 | ⭐⭐⭐ | 中等(需要抽象工厂和子类) |
| 抽象工厂 | ⭐⭐ | 复杂(需要多个抽象产品和实现) |
| 建造者 | ⭐⭐⭐ | 中等(需要builder类和多个方法) |
| 原型 | ⭐⭐⭐⭐ | 较简单(主要处理克隆逻辑) |
6.3 设计模式组合使用
创建型模式常常组合使用以获取更好的设计效果:
- 工厂方法+单例:工厂本身是单例,确保工厂全局唯一
- 抽象工厂+工厂方法:用工厂方法实现抽象工厂
- 建造者+原型:用原型模式复制建造者创建的基础对象
- 单例+原型:单例管理器存储原型对象
- 抽象工厂+建造者:工厂创建建造者对象
组合模式示例
java
1// 单例工厂示例2public class SingletonFactory {3 private static SingletonFactory instance = new SingletonFactory();4 private Map<String, Product> products = new HashMap<>();5 6 private SingletonFactory() {7 // 注册产品原型8 products.put("default", new ConcreteProduct());9 }10 11 public static SingletonFactory getInstance() {12 return instance;13 }14 15 public Product createProduct(String type) {16 Product prototype = products.get(type);17 if (prototype == null) {18 prototype = products.get("default");19 }20 // 使用原型模式创建产品21 return prototype.clone();22 }23}创建型模式选择原则
- 单例模式:需要全局唯一实例时使用
- 工厂方法:需要延迟实例化时使用
- 抽象工厂:需要创建产品族时使用
- 建造者模式:需要构建复杂对象时使用
- 原型模式:需要对象克隆时使用
通过本章的学习,你应该已经掌握了五种创建型模式的原理、实现方式和应用场景。在实际项目中,要根据具体需求选择合适的创建型模式,并注意线程安全和性能优化问题。
参与讨论