定义
工厂方法模式是一种创建型设计模式, 又称为工厂模式。其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
也就是说它定义了一个创建对象的接口,但将具体实例化操作推迟到子类中。也就是说,父类提供创建对象的方法, 并且允许子类决定实例化对象的类型。这样做的好处是可以使一个类的实例化延迟到其子类中进行,从而提供更大的灵活性和扩展性。
和模板方法的定义有一点像。但是工厂方法着重于对象的创建过程,它提供了一种灵活的实例化策略;而模板方法则专注于定义算法的框架,将固定不变的“模板”放在父类,变化的部分放在子类中,由子类去实现。
所以当需要控制对象的创建过程,尤其是当类型的选择依赖于运行时信息时,应考虑使用工厂方法。而当多个类有相似的操作流程,但部分步骤需要定制时,模板方法是更合适的选择。
工厂的实现构成
构成
1. 产品接口(Product Interface):定义了所有具体产品需要实现的接口或抽象类,规范了产品的公共接口。
2. 具体产品类(Concrete Product):实现了产品接口的具体类,不同的具体产品代表不同的产品种类。
3. 工厂接口(Factory Interface):声明了一个创建产品对象的方法,但不负责实际的产品创建,而是交由它的实现类去完成。
4. 具体工厂类(Concrete Factory):实现了工厂接口,负责实例化具体的产品对象。每个具体工厂类都与一种具体产品类相对应,负责创建该类型的产品对象。
UML图
工厂方法的代码实现
产品接口:// 产品接口:日志记录器接口
interface Logger {
void log(String message);
}
具体产品类:
// 具体产品类:文件日志记录器
class FileLogger implements Logger {
public void log(String message) {
System.out.println("File: " + message);
}
}
// 具体产品类:数据库日志记录器
class DatabaseLogger implements Logger {
public void log(String message) {
System.out.println("Database: " + message);
}
}
工厂接口:
// 工厂接口
interface LoggerFactory {
Logger createLogger();
}
具体工厂类:
// 具体工厂类:文件日志记录器工厂
class FileLoggerFactory implements LoggerFactory {
public Logger createLogger() {
return new FileLogger();
}
}
// 具体工厂类:数据库日志记录器工厂
class DatabaseLoggerFactory implements LoggerFactory {
public Logger createLogger() {
return new DatabaseLogger();
}
}
客户端代码:
public class Client {
public static void main(String[] args) {
// 动态选择日志记录器工厂,可以通过配置或其他逻辑来决定使用哪种工厂
LoggerFactory factory;
String loggerType = "database"; // 可以从配置文件或其他地方读取这个值
if ("file".equalsIgnoreCase(loggerType)) {
factory = new FileLoggerFactory();
} else if ("database".equalsIgnoreCase(loggerType)) {
factory = new DatabaseLoggerFactory();
} else {
throw new IllegalArgumentException("Unknown logger type: " + loggerType);
}
// 使用工厂创建日志记录器
Logger logger = factory.createLogger();
logger.log("A log message");
}
}
总结
优点
1. 解耦:将具体产品的创建和使用分离,使得系统更易于扩展和维护。
2. 灵活性:可以引入新的产品子类而不修改现有代码,符合开闭原则。
3. 单一职责原则:每个具体工厂负责创建相应的产品,职责单一明确。
缺点
1. 增加代码复杂度:需要定义多个子类来实现工厂方法,增加了系统的复杂度。
2. 类爆炸问题:对于每一种产品都需要一个对应的工厂类,可能导致类的数量急剧增加。
应用场景
1. 需要创建复杂对象:如果创建对象的过程比较复杂,可以使用工厂方法将对象的创建过程封装起来。
2. 具体类型在运行时决定:如果程序的具体类型需要在运行时才能确定,工厂方法是一个很好的选择。
3. 解耦:希望将程序的创建和使用,减少耦合,提高系统的灵活性和可维护性。
4. 系统未来可能需要引入新的功能类别:工厂方法可以方便地引入新产品而不影响现有系统。
简单工厂、工厂方法和抽象工厂的区别
1. 简单工厂:一个工厂方法用来创建不同类型的对象
2. 工厂方法:一个具体的工厂类创建一个对应的具体对象
3. 抽象工厂:一个具体的工厂类创建一系列相关的对象