工厂方法模式
工厂方法模式 (Factory Method Pattern)
定义: 工厂方法模式定义了一个创建对象的接口(工厂方法),但由子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类。
核心思想: 不再由一个“全能”的工厂类来创建所有的产品(像简单工厂那样),而是将创建具体产品的责任下放到各个子工厂(具体创建者)中。每个子工厂只负责创建一种特定的产品。
参与者 (Participants):
Product (抽象产品):
定义了工厂方法所创建的对象的接口。
在 Java 中通常是一个接口或抽象类。
ConcreteProduct (具体产品):
实现了 Product 接口。
是工厂方法创建的目标。
Creator (抽象创建者 / 抽象工厂):
声明了工厂方法 factoryMethod(),该方法返回一个 Product 类型的对象。
Creator 也可以定义一个默认的工厂方法实现,返回一个默认的 ConcreteProduct 对象。
通常是一个抽象类,也可以是接口。如果它是抽象类,可以包含一些依赖于 Product 对象的业务逻辑,这些逻辑会调用抽象的 factoryMethod()。
ConcreteCreator (具体创建者 / 具体工厂):
实现了 Creator 接口或继承了 Creator 抽象类。
重写(或实现)工厂方法 factoryMethod() 以返回一个具体的 ConcreteProduct 实例。
类图 (UML):
classDiagram class Product { <<Interface>> +operation() } class ConcreteProductA { +operation() } class ConcreteProductB { +operation() } Product <|.. ConcreteProductA Product <|.. ConcreteProductB class Creator { <<Abstract>> +factoryMethod(): Product +someOperation() } class ConcreteCreatorA { +factoryMethod(): Product } class ConcreteCreatorB { +factoryMethod(): Product } Creator <|-- ConcreteCreatorA Creator <|-- ConcreteCreatorB ConcreteCreatorA ..> ConcreteProductA : creates ConcreteCreatorB ..> ConcreteProductB : creates Client --> Creator Client --> Product
Creator 的 someOperation() 方法通常会调用 factoryMethod() 来获取一个 Product 对象,然后对这个对象执行操作。
优点:
良好的开闭原则 (Open/Closed Principle): 当需要增加新的产品时,只需要增加一个新的具体产品类和一个对应的具体工厂类,而不需要修改原有的工厂类和产品类代码。
解耦: 将对象的创建和使用分离。客户端只需要知道抽象工厂和抽象产品,而不需要知道具体是哪个工厂创建了哪个具体产品。
灵活性高: 子类可以覆盖工厂方法来改变创建的产品类型。每个具体工厂只负责创建一种具体产品,职责单一。
封装性好: 将创建产品的代码封装在具体工厂的工厂方法中,客户端不需要关心创建细节。
缺点:
增加类的数量: 每增加一个产品,就需要增加一个具体产品类和一个相应的具体工厂类,这使得系统中的类数量成倍增加,增加了系统的复杂度。
适用场景:
当一个类不知道它所必须创建的对象的类的时候。
当一个类希望由它的子类来指定它所创建的对象的时候。
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
Java 代码示例:
假设我们要创建一个日志记录器系统,可以记录到文件或控制台。
1. Product (抽象产品) - Logger 接口
// Logger.java public interface Logger { void log(String message); }
2. ConcreteProduct (具体产品) - FileLogger 和 ConsoleLogger
// FileLogger.java public class FileLogger implements Logger { @Override public void log(String message) { System.out.println("Logging to File: " + message); // 实际的文件写入逻辑会更复杂 } } // ConsoleLogger.java public class ConsoleLogger implements Logger { @Override public void log(String message) { System.out.println("Logging to Console: " + message); } }
3. Creator (抽象创建者 / 抽象工厂) - LoggerFactory 抽象类
// LoggerFactory.java public abstract class LoggerFactory { // 这是核心的工厂方法 public abstract Logger createLogger(); // 也可以定义一些通用的操作,这些操作会使用工厂方法创建的产品 public void writeLog(String message) { Logger logger = createLogger(); // 使用工厂方法创建产品 logger.log(message); } }
4. ConcreteCreator (具体创建者 / 具体工厂) - FileLoggerFactory 和 ConsoleLoggerFactory
// FileLoggerFactory.java public class FileLoggerFactory extends LoggerFactory { @Override public Logger createLogger() { // 返回具体的产品:FileLogger System.out.println("FileLoggerFactory: Creating FileLogger."); return new FileLogger(); } } // ConsoleLoggerFactory.java public class ConsoleLoggerFactory extends LoggerFactory { @Override public Logger createLogger() { // 返回具体的产品:ConsoleLogger System.out.println("ConsoleLoggerFactory: Creating ConsoleLogger."); return new ConsoleLogger(); } }
5. Client (客户端) - 使用工厂方法
// Client.java (or Main class) public class Client { public static void main(String[] args) { // 需要文件日志记录器 LoggerFactory fileFactory = new FileLoggerFactory(); Logger fileLogger = fileFactory.createLogger(); // 直接调用工厂方法获取产品 fileLogger.log("This is a message for the file logger."); // 或者通过抽象工厂的通用方法 fileFactory.writeLog("Another message for the file logger via writeLog method."); System.out.println("------------------------------------"); // 需要控制台日志记录器 LoggerFactory consoleFactory = new ConsoleLoggerFactory(); Logger consoleLogger = consoleFactory.createLogger(); consoleLogger.log("This is a message for the console logger."); consoleFactory.writeLog("Another message for the console logger via writeLog method."); // 演示开闭原则:如果将来需要 DatabaseLogger // 1. 创建 DatabaseLogger implements Logger // 2. 创建 DatabaseLoggerFactory extends LoggerFactory (重写 createLogger 返回 DatabaseLogger) // 客户端代码可以这样使用,而不需要修改 LoggerFactory 或已有的工厂和产品: // LoggerFactory dbFactory = new DatabaseLoggerFactory(); // dbFactory.writeLog("This message goes to the database."); } }
输出:
FileLoggerFactory: Creating FileLogger. Logging to File: This is a message for the file logger. FileLoggerFactory: Creating FileLogger. Logging to File: Another message for the file logger via writeLog method. ------------------------------------ ConsoleLoggerFactory: Creating ConsoleLogger. Logging to Console: This is a message for the console logger. ConsoleLoggerFactory: Creating ConsoleLogger. Logging to Console: Another message for the console logger via writeLog method.
总结: 工厂方法模式通过引入抽象工厂和具体工厂,将对象的创建过程延迟到子类中进行。客户端代码仅依赖于抽象工厂和抽象产品,从而实现了创建过程的解耦和灵活性。当你希望系统能够轻松扩展新的产品类型时,工厂方法是一个很好的选择。