工厂方法模式(Factory Method Pattern)深入解析
工厂方法模式(Factory Method Pattern)是设计模式中的一种创建型模式,它提供了一个创建对象的接口,但由子类决定实例化哪一个类。工厂方法模式使得一个类的实例化延迟到其子类。
本文将深入探讨工厂方法模式的原理、实现方法,以及实际应用场景,并通过代码示例来帮助大家更好地理解这一设计模式的使用。
1. 工厂方法模式概述
工厂方法模式是一种将对象的创建与使用分离的设计模式。在传统的面向对象编程中,类通过构造函数来直接创建对象。而工厂方法模式则将这个过程交由工厂类来负责。工厂方法模式的核心思想是:定义一个创建对象的接口,但由子类决定要实例化的具体类。
1.1 关键概念
- 工厂方法(Factory Method):负责创建对象的接口或抽象方法。
- 具体工厂(Concrete Factory):实现工厂方法的类,用来创建具体的产品对象。
- 产品(Product):工厂方法所创建的对象类型。
- 抽象产品(Abstract Product):产品的接口或抽象类。
1.2 UML类图
工厂方法模式的类图结构通常如下所示:
+---------------------+
| Creator (抽象类) |
+---------------------+
| + factoryMethod() |<------------------------------------+
+---------------------+ |
^ |
| |
+---------------------+ +------------------+
| ConcreteCreator 1 | | ConcreteCreator 2 |
+---------------------+ +------------------+
| + factoryMethod() | | + factoryMethod() |
+---------------------+ +------------------+
| |
| |
+--------------------+ +--------------------+
| Product (抽象类) | | Product (抽象类) |
+--------------------+ +--------------------+
^ ^
| |
+--------------------+ +--------------------+
| ConcreteProduct 1 | | ConcreteProduct 2 |
+--------------------+ +--------------------+
Creator
:声明了工厂方法,并且负责调用具体的工厂方法来生成产品。ConcreteCreator
:实现具体的工厂方法,返回一个具体的产品实例。Product
:表示产品接口或抽象类。ConcreteProduct
:具体的产品类,实现了产品接口。
2. 工厂方法模式的实现
2.1 定义产品接口
首先,我们需要定义产品接口,该接口由所有具体产品类实现:
// 产品接口
public interface Product {
void operation();
}
2.2 定义具体产品
然后,我们定义具体的产品类,它们实现了Product
接口:
// 具体产品 1
public class ConcreteProduct1 implements Product {
@Override
public void operation() {
System.out.println("Operation of ConcreteProduct1");
}
}
// 具体产品 2
public class ConcreteProduct2 implements Product {
@Override
public void operation() {
System.out.println("Operation of ConcreteProduct2");
}
}
2.3 定义工厂接口
接下来,我们定义一个抽象的工厂类,该类声明了工厂方法:
// 工厂接口
public interface Creator {
Product factoryMethod();
}
2.4 定义具体工厂
然后,我们定义具体工厂类,这些类负责实例化具体的产品:
// 具体工厂 1
public class ConcreteCreator1 implements Creator {
@Override
public Product factoryMethod() {
return new ConcreteProduct1();
}
}
// 具体工厂 2
public class ConcreteCreator2 implements Creator {
@Override
public Product factoryMethod() {
return new ConcreteProduct2();
}
}
2.5 客户端代码
最后,客户端代码通过工厂接口来获取产品,而无需关心具体的产品类:
public class Client {
public static void main(String[] args) {
Creator creator1 = new ConcreteCreator1();
Product product1 = creator1.factoryMethod();
product1.operation();
Creator creator2 = new ConcreteCreator2();
Product product2 = creator2.factoryMethod();
product2.operation();
}
}
2.6 运行结果
Operation of ConcreteProduct1
Operation of ConcreteProduct2
3. 工厂方法模式的优缺点
3.1 优点
- 解耦:工厂方法模式将对象的创建与使用分离,客户端不需要知道具体的产品类,只需要依赖工厂类来获取对象。
- 扩展性好:可以通过添加新的具体工厂和产品类来扩展系统,而不需要修改现有的代码。
- 符合开闭原则:当需要扩展时,可以通过增加新的产品和工厂类来实现,而无需修改已有代码。
3.2 缺点
- 类的数量增加:引入了多个工厂类和产品类,增加了系统的复杂度和类的数量。
- 增加代码的复杂性:每增加一个产品类就必须增加一个具体的工厂类,维护起来较为繁琐。
4. 工厂方法模式的应用场景
工厂方法模式适用于以下几种场景:
- 产品类的创建过程复杂:如果产品类的创建过程较为复杂,通过工厂方法模式可以将创建逻辑集中到工厂类中,简化客户端代码。
- 客户端不知道具体的产品类:当系统中的产品类很多,而客户端不关心具体的产品类时,工厂方法模式可以将产品的创建过程封装起来。
- 需要扩展新的产品时:当产品种类经常变化时,通过增加新的工厂和产品类,可以灵活地扩展系统,而不影响现有的代码。
4.1 实际案例:日志系统
假设我们需要实现一个跨平台的日志系统,不同的日志记录方式可能对应不同的日志平台(如:控制台日志、文件日志、数据库日志等)。使用工厂方法模式,可以方便地扩展支持不同的日志记录方式:
// 产品接口
public interface Logger {
void log(String message);
}
// 具体产品:控制台日志
public class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Console Logger: " + message);
}
}
// 具体产品:文件日志
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("File Logger: " + message);
}
}
// 工厂接口
public interface LoggerFactory {
Logger createLogger();
}
// 具体工厂:控制台日志工厂
public class ConsoleLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new ConsoleLogger();
}
}
// 具体工厂:文件日志工厂
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
// 客户端
public class LogClient {
public static void main(String[] args) {
LoggerFactory loggerFactory = new ConsoleLoggerFactory();
Logger logger = loggerFactory.createLogger();
logger.log("This is a log message.");
}
}
4.2 扩展
当需要增加一个新的日志类型(比如数据库日志)时,我们只需要增加一个新的具体产品类(DatabaseLogger
)和一个新的工厂类(DatabaseLoggerFactory
),而不需要修改现有代码。
5. 总结
工厂方法模式通过将对象创建的过程交给子类来完成,从而解耦了客户端与产品类的直接关系。通过代码示例,我们可以看到它在实现上非常直观,且适用于一些场景下产品创建较为复杂或不确定的情况。