当前位置: 首页 > news >正文

设计模式之:工厂方法模式

文章目录

    • 什么是工厂方法模式?
    • 核心思想
    • 模式结构
    • 完整示例:日志记录系统
      • 1. 定义抽象产品
      • 2. 实现具体产品
      • 3. 定义抽象工厂
      • 4. 实现具体工厂
      • 5. 客户端使用示例
      • 6. 进阶示例:配置化的日志工厂
    • 工厂方法模式的优点
      • 1. 符合开闭原则
      • 2. 客户端与具体产品解耦
      • 3. 提高代码的可测试性
    • 工厂方法模式的缺点
      • 1. 类的数量增加
      • 2. 增加了系统的复杂性
    • 适用场景
    • 与简单工厂模式的对比
    • 最佳实践
      • 1. 使用依赖注入
      • 2. 结合配置文件
      • 3. 使用泛型增强类型安全
    • 总结

什么是工厂方法模式?

工厂方法模式(Factory Method Pattern)是一种经典的创建型设计模式,它定义了一个创建对象的接口,但让子类决定要实例化哪一个类。工厂方法让类的实例化推迟到子类,完美遵循了“开闭原则”,实现了对象创建的可扩展性。

核心思想

工厂方法模式的核心是:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化延迟到子类进行。

模式结构

工厂方法模式包含四个核心角色:

  1. 抽象产品(Product):定义产品的接口
  2. 具体产品(Concrete Product):实现抽象产品接口的具体类
  3. 抽象工厂(Creator):声明工厂方法,返回产品对象
  4. 具体工厂(Concrete Creator):重写工厂方法,返回具体产品实例

完整示例:日志记录系统

让我们通过一个完整的日志记录系统来深入理解工厂方法模式。

1. 定义抽象产品

/*** 日志记录器接口 - 抽象产品角色* 定义日志记录的基本操作*/
public interface Logger {/*** 记录信息日志* @param message 日志信息*/void info(String message);/*** 记录错误日志* @param message 错误信息*/void error(String message);/*** 记录警告日志* @param message 警告信息*/void warn(String message);/*** 记录调试日志* @param message 调试信息*/void debug(String message);
}

2. 实现具体产品

/*** 文件日志记录器 - 具体产品角色* 将日志记录到文件中*/
public class FileLogger implements Logger {private String filePath;public FileLogger(String filePath) {this.filePath = filePath;System.out.println("初始化文件日志记录器,文件路径: " + filePath);}@Overridepublic void info(String message) {String log = String.format("[INFO] %s %s", getTimestamp(), message);writeToFile(log);}@Overridepublic void error(String message) {String log = String.format("[ERROR] %s %s", getTimestamp(), message);writeToFile(log);}@Overridepublic void warn(String message) {String log = String.format("[WARN] %s %s", getTimestamp(), message);writeToFile(log);}@Overridepublic void debug(String message) {String log = String.format("[DEBUG] %s %s", getTimestamp(), message);writeToFile(log);}private void writeToFile(String log) {// 模拟写入文件操作System.out.println("写入文件[" + filePath + "]: " + log);}private String getTimestamp() {return java.time.LocalDateTime.now().toString();}
}/*** 控制台日志记录器 - 具体产品角色* 将日志输出到控制台*/
public class ConsoleLogger implements Logger {@Overridepublic void info(String message) {System.out.println("\u001B[32m[INFO] " + getTimestamp() + " " + message + "\u001B[0m");}@Overridepublic void error(String message) {System.out.println("\u001B[31m[ERROR] " + getTimestamp() + " " + message + "\u001B[0m");}@Overridepublic void warn(String message) {System.out.println("\u001B[33m[WARN] " + getTimestamp() + " " + message + "\u001B[0m");}@Overridepublic void debug(String message) {System.out.println("\u001B[36m[DEBUG] " + getTimestamp() + " " + message + "\u001B[0m");}private String getTimestamp() {return java.time.LocalDateTime.now().toString();}
}/*** 数据库日志记录器 - 具体产品角色* 将日志记录到数据库中*/
public class DatabaseLogger implements Logger {private String dataSource;public DatabaseLogger(String dataSource) {this.dataSource = dataSource;System.out.println("初始化数据库日志记录器,数据源: " + dataSource);}@Overridepublic void info(String message) {String log = String.format("INSERT INTO logs (level, message, timestamp) VALUES ('INFO', '%s', '%s')", message, getTimestamp());executeSQL(log);}@Overridepublic void error(String message) {String log = String.format("INSERT INTO logs (level, message, timestamp) VALUES ('ERROR', '%s', '%s')", message, getTimestamp());executeSQL(log);}@Overridepublic void warn(String message) {String log = String.format("INSERT INTO logs (level, message, timestamp) VALUES ('WARN', '%s', '%s')", message, getTimestamp());executeSQL(log);}@Overridepublic void debug(String message) {String log = String.format("INSERT INTO logs (level, message, timestamp) VALUES ('DEBUG', '%s', '%s')", message, getTimestamp());executeSQL(log);}private void executeSQL(String sql) {// 模拟执行SQLSystem.out.println("执行SQL: " + sql);}private String getTimestamp() {return java.time.LocalDateTime.now().toString();}
}

3. 定义抽象工厂

/*** 日志记录器工厂接口 - 抽象工厂角色* 声明工厂方法,由子类实现具体创建逻辑*/
public interface LoggerFactory {/*** 工厂方法 - 创建日志记录器* @return 日志记录器实例*/Logger createLogger();/*** 使用日志记录器记录信息* @param message 日志信息*/default void logInfo(String message) {Logger logger = createLogger();logger.info(message);}/*** 使用日志记录器记录错误* @param message 错误信息*/default void logError(String message) {Logger logger = createLogger();logger.error(message);}
}

4. 实现具体工厂

/*** 文件日志记录器工厂 - 具体工厂角色* 负责创建文件日志记录器*/
public class FileLoggerFactory implements LoggerFactory {private String filePath;public FileLoggerFactory(String filePath) {this.filePath = filePath;}@Overridepublic Logger createLogger() {return new FileLogger(filePath);}
}/*** 控制台日志记录器工厂 - 具体工厂角色* 负责创建控制台日志记录器*/
public class ConsoleLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new ConsoleLogger();}
}/*** 数据库日志记录器工厂 - 具体工厂角色* 负责创建数据库日志记录器*/
public class DatabaseLoggerFactory implements LoggerFactory {private String dataSource;public DatabaseLoggerFactory(String dataSource) {this.dataSource = dataSource;}@Overridepublic Logger createLogger() {return new DatabaseLogger(dataSource);}
}

5. 客户端使用示例

/*** 应用程序类 - 客户端代码* 演示工厂方法模式的使用*/
public class Application {public static void main(String[] args) {System.out.println("=== 工厂方法模式演示 ===\n");// 使用控制台日志System.out.println("1. 使用控制台日志记录器:");useConsoleLogger();// 使用文件日志System.out.println("\n2. 使用文件日志记录器:");useFileLogger();// 使用数据库日志System.out.println("\n3. 使用数据库日志记录器:");useDatabaseLogger();// 演示多态性System.out.println("\n4. 演示多态性:");demonstratePolymorphism();}private static void useConsoleLogger() {LoggerFactory factory = new ConsoleLoggerFactory();Logger logger = factory.createLogger();logger.info("应用程序启动成功");logger.warn("内存使用率较高");logger.error("数据库连接失败");logger.debug("调试信息: 变量值 = 100");}private static void useFileLogger() {LoggerFactory factory = new FileLoggerFactory("/var/log/myapp.log");Logger logger = factory.createLogger();logger.info("用户登录成功");logger.error("文件上传失败");// 使用默认方法factory.logInfo("通过工厂默认方法记录日志");}private static void useDatabaseLogger() {LoggerFactory factory = new DatabaseLoggerFactory("jdbc:mysql://localhost:3306/logs");Logger logger = factory.createLogger();logger.info("订单创建成功");logger.error("支付处理异常");}private static void demonstratePolymorphism() {// 多态性的体现:可以轻松切换不同的日志实现LoggerFactory[] factories = {new ConsoleLoggerFactory(),new FileLoggerFactory("/tmp/app.log"),new DatabaseLoggerFactory("jdbc:mysql://localhost:3306/app")};for (LoggerFactory factory : factories) {System.out.println("\n使用 " + factory.getClass().getSimpleName() + ":");factory.logInfo("这是一条测试日志信息");factory.logError("这是一个测试错误信息");}}
}

6. 进阶示例:配置化的日志工厂

/*** 配置化日志工厂 - 根据配置创建不同的日志记录器*/
public class ConfigurableLoggerFactory implements LoggerFactory {private LoggerConfig config;public ConfigurableLoggerFactory(LoggerConfig config) {this.config = config;}@Overridepublic Logger createLogger() {switch (config.getType()) {case CONSOLE:return new ConsoleLogger();case FILE:return new FileLogger(config.getFilePath());case DATABASE:return new DatabaseLogger(config.getDataSource());default:throw new IllegalArgumentException("不支持的日志类型: " + config.getType());}}
}/*** 日志配置类*/
public class LoggerConfig {private LoggerType type;private String filePath;private String dataSource;public LoggerConfig(LoggerType type, String filePath, String dataSource) {this.type = type;this.filePath = filePath;this.dataSource = dataSource;}// Getter 方法public LoggerType getType() { return type; }public String getFilePath() { return filePath; }public String getDataSource() { return dataSource; }
}/*** 日志类型枚举*/
public enum LoggerType {CONSOLE, FILE, DATABASE
}

工厂方法模式的优点

1. 符合开闭原则

// 添加新的日志类型时,不需要修改现有代码
public class CloudLogger implements Logger {// 实现云日志记录...
}public class CloudLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new CloudLogger(); // 新增工厂,不修改现有代码}
}

2. 客户端与具体产品解耦

public class BusinessService {private LoggerFactory loggerFactory;public BusinessService(LoggerFactory loggerFactory) {this.loggerFactory = loggerFactory; // 依赖抽象,不依赖具体实现}public void processBusiness() {Logger logger = loggerFactory.createLogger();logger.info("业务处理开始");// 业务逻辑...logger.info("业务处理完成");}
}

3. 提高代码的可测试性

// 测试时可以使用Mock工厂
public class TestLoggerFactory implements LoggerFactory {@Overridepublic Logger createLogger() {return new MockLogger(); // 返回测试用的Mock对象}
}

工厂方法模式的缺点

1. 类的数量增加

每个具体产品都需要对应一个具体工厂类,会导致系统中类的数量成对增加。

2. 增加了系统的复杂性

对于简单对象的创建,使用工厂方法模式可能会显得过于复杂。

适用场景

  1. 无法预知对象的确切类型:运行时才能确定要创建的对象
  2. 希望扩展产品类型:需要添加新产品时不影响现有代码
  3. 需要解耦客户端和具体产品:客户端只关心产品接口
  4. 需要为不同的上下文提供不同的产品实现

与简单工厂模式的对比

特性简单工厂模式工厂方法模式
创建逻辑集中在单个工厂类分散在多个具体工厂类
开闭原则违反(修改需要改动工厂类)符合(扩展新工厂即可)
复杂度相对简单相对复杂
灵活性较低较高
适用场景产品类型固定,变化较少产品类型可能扩展

最佳实践

1. 使用依赖注入

public class ApplicationContext {private static Map<String, LoggerFactory> factories = new HashMap<>();static {// 注册所有工厂factories.put("console", new ConsoleLoggerFactory());factories.put("file", new FileLoggerFactory("/app.log"));}public static LoggerFactory getLoggerFactory(String type) {return factories.get(type);}
}

2. 结合配置文件

// 通过配置文件决定使用哪个工厂
Properties config = loadConfig();
String factoryType = config.getProperty("logger.factory");
LoggerFactory factory = ApplicationContext.getLoggerFactory(factoryType);

3. 使用泛型增强类型安全

public interface LoggerFactory<T extends Logger> {T createLogger();
}public class FileLoggerFactory implements LoggerFactory<FileLogger> {@Overridepublic FileLogger createLogger() {return new FileLogger("/app.log");}
}

总结

工厂方法模式通过将对象的创建延迟到子类,完美解决了简单工厂模式违反开闭原则的问题。它提供了一种灵活的扩展机制,使得系统能够轻松应对变化。

核心价值:

  • 真正实现了面向对象设计的"开闭原则"
  • 提供了优秀的扩展性和维护性
  • 实现了创建逻辑与使用逻辑的彻底分离
  • 为框架设计和组件化提供了坚实基础

掌握工厂方法模式,能够帮助我们在面对复杂对象创建场景时,设计出更加灵活、可维护的系统架构。

http://www.dtcms.com/a/495314.html

相关文章:

  • 西宁市精神文明建设网站餐饮店面装饰设计
  • 对营销网站建设评估及分析佛山顺德做网站
  • 高并发系统架构设计原则:无状态、水平扩展、异步化、缓存优先
  • 系统架构设计师备考第45天——软件架构演化评估方法和维护
  • 基于SpringBoot+Vue的社区诊所管理系统(AI问答、webSocket实时聊天、Echarts图形化分析)
  • 【MySQL】第二章 基本的SELECT语句
  • Linux中软中断tasklet任务队列初始化
  • 网站制作的重要流程世界优秀摄影作品网站
  • 技术剖析:智能体工作流与RPA流程自动化的架构差异与融合实现
  • 深圳比斯特自动化|圆柱电池测试设备核心功能与技术发展解析
  • 【软考备考】系统架构设计需要考虑的因素 性能 、安全、成本、可维护性详解知识点五
  • 面试反馈 Spring Cloud 的25连环炮
  • 第八篇: `lsmod`, `modinfo`, `modprobe` - 深入内核模块
  • aspx网站服务器失去响应天工网工程新希望官网
  • 网站服务器要多少钱【邯郸网络推广公司|邯郸网络营销公司】
  • 做网站用什么域名比较好找公司开发网站
  • 【Python】求解GPS未知及高斯噪声
  • Linux 教程:如何查找服务器中的大文件
  • 计算机网络基础篇——应用层
  • 2025年主流外贸管理软件深度测评和选型策略咨询报告
  • 玩Android Harmony next版,通过项目了解harmony项目快速搭建开发
  • 公司免费网站域名申请免费网址
  • 华为鲲鹏 Aarch64 环境下多 Oracle 数据库汇聚操作指南 CMP(类 Cloudera CDP 7.3)
  • Chromedriver放项目里就行!Selenium 3 和 4 指定路径方法对比 + 兼容写法
  • Spring Boot 项目, idea 控制台日志设置彩色
  • wap网站建设好不好百度小程序官方收费标准
  • Go语言数据竞争Data Race 问题怎么检测?怎么解决?
  • 作为项目经理,如何做好项目复盘?
  • 网站建设百度不通过杭州建站模板系统
  • A函数里调用B函数 ,且往B函数里传了个二级指针,并在B返回后,释放该指针