工厂方法模式(Factory Method Pattern) 是设计模式中的一种创建型模式,它定义了一个用于创建对象的接口,但让子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。工厂方法模式是一种非常实用的模式,特别是在处理大量具有共同接口的类时,系统要基于多个扩展类的类型来决定实例化哪一个类。
一、工厂方法模式概述
1. 模式动机
在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的创建逻辑可能经常变化,但它却拥有比较稳定的接口。如何应对这种变化?如何设计出满足需求的类结构?工厂方法模式提供了一种解决方案。
2. 模式定义
工厂方法模式(Factory Method Pattern)又称为多态性工厂模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
3. 模式结构
工厂方法模式包含以下四个角色:
Product(抽象产品):定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的共同父类或接口。
ConcreteProduct(具体产品):实现了抽象产品接口的具体产品对象,被具体的工厂类所创建。
Creator(抽象工厂):声明了工厂方法(Factory Method),用于返回一个产品。工厂方法是一个返回抽象产品类型的方法,其子类可以覆盖该方法以返回不同的具体产品类型。
ConcreteCreator(具体工厂):实现了抽象工厂中的工厂方法,通过客户调用以返回具体产品类的实例。
4. 优缺点
优点:
用户只需要知道具体工厂类的名称就可得到所要的产品,无须知道产品的具体创建过程。
灵活性增强,对于新产品的创建,只需继承一个具体工厂类或者添加一个具体工厂类,就可以实现扩展。
缺点:
类的个数容易过多,增加系统的复杂度,因为每增加一个产品,就需要增加一个具体产品类和一个具体工厂类。
系统扩展繁琐,如果要增加一个新的产品,除了增加新的产品类外,还需要增加新的具体工厂类,并在客户端中增加新的工厂类的实例。
二、工厂方法模式实现
1. 示例场景
假设我们有一个日志系统,需要支持多种日志记录方式(如文件日志、数据库日志、控制台日志等)。每种日志记录方式都有自己特定的实现,但对外都提供一个统一的接口。我们可以使用工厂方法模式来设计这个日志系统。
2. 角色定义
Log(抽象产品):定义日志记录的接口。
FileLog(具体产品):实现文件日志记录。
DatabaseLog(具体产品):实现数据库日志记录。
LogFactory(抽象工厂):声明创建日志记录的工厂方法。
FileLogFactory(具体工厂):实现创建文件日志记录的工厂。
DatabaseLogFactory(具体工厂):实现创建数据库日志记录的工厂。
3. Java代码实现
// 抽象产品:日志记录接口
interface Log {
void writeLog(String message);
}
// 具体产品:文件日志记录
class FileLog implements Log {
@Override
public void writeLog(String message) {
System.out.println("FileLog: " + message);
}
}
// 具体产品:数据库日志记录
class DatabaseLog implements Log {
@Override
public void writeLog(String message) {
System.out.println("DatabaseLog: " + message);
}
}
// 抽象工厂:日志工厂接口
interface LogFactory {
Log createLog();
}
// 具体工厂:文件日志工厂
class FileLogFactory implements LogFactory {
@Override
public Log createLog() {
return new FileLog();
}
}
// 具体工厂:数据库日志工厂
class DatabaseLogFactory implements LogFactory {
@Override
public Log createLog() {
return new DatabaseLog();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 使用文件日志
LogFactory fileLogFactory = new FileLogFactory();
Log fileLog = fileLogFactory.createLog();
fileLog.writeLog("This is a file log.");
// 使用数据库日志
LogFactory databaseLogFactory = new DatabaseLogFactory();
Log databaseLog = databaseLogFactory.createLog();
databaseLog.writeLog("This is a database log.");
}
}
三、工厂方法模式的应用场景
当一个类不知道它所必须创建的对象的类的时候。
当一个类希望由它的子类来指定它所创建的对象的时候。
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
四、工厂方法模式的扩展
1. 工厂方法模式的变体
简单工厂模式:简单工厂模式不属于GOF的23种设计模式之一,但它是一种非常常用的实例化对象的模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,类似于一个工厂类负责创建所有实例。
抽象工厂模式:抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
2. 工厂方法模式与其他模式的结合
与单例模式结合:在某些情况下,工厂类本身就是一个单例,负责创建和管理所有的产品对象。
与策略模式结合:工厂方法模式可以与策略模式结合使用,将不同的算法封装成不同的产品类,由工厂类根据需求创建相应的算法对象。
五、总结
工厂方法模式是一种非常实用的设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类。这种方式将对象的创建逻辑封装在工厂类中,使得客户端代码与具体的产品类解耦,提高了系统的灵活性和可扩展性。同时,工厂方法模式也具有一定的局限性,如类的个数容易过多、系统扩展繁琐等。因此,在设计系统时,需要根据实际情况选择合适的设计模式。