模式概述
- 工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,弥补了缺陷。他也被称为
虚拟构造器模式
或者多态工厂模式
。 - 先定义一个
抽象工厂类
,再定义具体工厂类
去实现抽象工厂类的方法,这种抽象化的结果是:可以在不修改具体工厂类的情况下引进新的产品,如果出现新的功能,只需要为这个功能定义一个具体的工厂类。就可以创建出该功能的实例,这种改进方案,就叫做工厂方法模式。 - 在工厂方法模式中,工厂父类负责定义创建产品对象的
公共接口
,而工厂子类负责生成具体的产品对象
,这样做得目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定久经应该实例化哪一个具体产品类。 - 总结:定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化,工厂方法模式让一个类的实例化延迟到其子类。
模式结构
- 抽象产品(定义产品的接口,产品对象的公共父类)
- 具体产品(实现产品的接口)
- 抽象工厂(声明工厂方法,返回一个产品)
- 具体工厂(抽象工厂的子类,客户端调用,返回一个具体的实例)
代码实现
需求: 日志记录器可以通过很多途径保存日志,用户可以修改配置文件,灵活的更换日志记录的方式,为了更好的封装记录器的初始化过程,并保证多种记录器切换的灵活性,使用工厂方法模式设计该系统。
- 抽象产品接口:
Logger
//抽象产品类
public interface Logger {
public void writeLog();
}
- 具体产品实现:
DatabaseLogger
,FileLogger
import com.daq.factorymethod.Logger;
public class DatabaseLogger implements Logger {
@Override
public void writeLog() {
System.out.println("数据库日志记录");
}
}
import com.daq.factorymethod.Logger;
public class FileLogger implements Logger {
@Override
public void writeLog() {
System.out.println("文件日志记录");
}
}
- 抽象工厂接口:
LoggerFactory
import com.daq.factorymethod.Logger;
//抽象工厂接口
public interface LoggerFactory {
//抽象工厂方法
public Logger createLogger();
}
- 具体工厂实现:
DatabaseLoggerFactory
,FileLoggerFactory
import com.daq.factory.LoggerFactory;
import com.daq.factorymethod.Logger;
import com.daq.factorymethod.Impl.DatabaseLogger;
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//连接数据库
//创建数据库日志记录器对象
Logger logger = new DatabaseLogger();
//初始化数据库日志记录器
return logger;
}
}
import com.daq.factory.LoggerFactory;
import com.daq.factorymethod.Logger;
import com.daq.factorymethod.Impl.FileLogger;
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
//创建文件日志记录对象
Logger logger = new FileLogger();
//创建文件
return logger;
}
}
- 客户端测试:
Client
import com.daq.factory.LoggerFactory;
import com.daq.factory.Impl.FileLoggerFactory;
import com.daq.factorymethod.Logger;
public class Client {
public static void main(String[] args) {
LoggerFactory factory;
Logger logger;
//具体工厂的实例
factory=new FileLoggerFactory();
logger=factory.createLogger();
logger.writeLog();
}
}
- 如果要增加新的功能,只需要对应的增加一个新的具体工厂类,然后在客户端代码中修改具体工厂类的类名,原有类库的代码无需修改。
- 通过引入配合文件并使用反射机制可以实现
在不修改客户端代码的基础上更换具体共产类
,系统更符合开闭原则,具备更好的扩展性。
工厂方法的隐藏
- 通过把业务方法调用移至工厂类中,可以直接使用工厂对象来调用产品对象的业务方法,客户端无需使用工厂方法来创建产品对象。
优缺点
-
优点:
①用户只需关心所需产品对应的工厂,无需关心创建细节。
②基于工厂角色和产品角色的多态性设计是工厂方法模式的关键,工厂方法模式之所以被称为多态工厂模式
,正是因为所有的具体工厂类都具有同一抽象父类。
③新增功能时,无需修改源码,只增添一个具体工厂和具体产品即可。 -
缺点:
①新增了产品类,意味着系统的复杂度要增加。
②代码中引入了抽象层,在客户端中也使用了抽象性进行定义,增加了理解难度。
应用场景
- 客户端不知道它所需要使用的类,因为客户端只需要知道所对应的工厂就行了。
- 抽象工厂类通过使用他的子类来指定创建哪个对象。在工厂方法模式中对于抽象工厂只需要提供一个创建产品的接口,而由其子类来决定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时子类对象将覆盖父类对象。