介绍
工厂方法是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。
场景
假如我们开发项目中的日志模块,业务初期只有控制台日志,大部分代码都在控制台日志类。随着业务发展,希望可以增加文件日志功能。
如果代码之间已经存在耦合关系,此时向程序添加新类并不是一件简单的事情。目前大部分代码都与控制台日志类有关。添加文件日志类需要修改全部代码,更可怕的是以后万一要拓展其他日志类,很可能需要再次大幅修改代码。
如此反复反复,恭喜成功诞生一份不可维护的祖传代码。 😂
解决方案
工厂方法模式建议使用特殊的工厂方法代替直接调用 new 关键字创建对象。工厂方法返回的对象通常被称作“产品”。
public abstract class Logger {
public abstract void log();
}
public class ConsoleLogger extends Logger {
@Override
public void log() {
System.out.println("我是控制台日志器!");
}
}
public class FileLogger extends Logger {
@Override
public void log() {
System.out.println("我是文件日志器!");
}
}
紧接着我们再创建一个工厂类,这里声明为抽象类,并且设置一个抽象方法,强制子类实现抽象方法。你也可以设置不设置成抽象类,在基础工厂方法中返回默认类型。
public abstract class LoggerFactory {
public abstract Logger createLogger();
}
public class ConsoleLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new ConsoleLogger();
}
}
public class FileLoggerFactory extends LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
乍看之下,工厂方法模式看起来毫无意义,只是改变了程序中调用构造函数的位置而已。但是我们可以在子类里重写工厂方法,从而改变其创建产品的类型。
但有一点需要注意,仅当这些产品具有共同的父类或者接口时,工厂子类才能返回不同类型的产品。同时工厂基类的工厂方法还应将其返回类型声明为共有接口。
只要产品类实现一个共同的接口,就可以将它传递给客户代码,而无需提供任何额外的数据。
public class Application {
private final LoggerFactory loggerFactory;
public Application(LoggerFactory loggerFactory) {
this.loggerFactory = loggerFactory;
}
public void run() {
Logger logger = loggerFactory.createLogger();
logger.log();
}
}
客户端代码仅通过抽象类型使用工厂和产品,如需要添加新的产品,仅需实现工厂抽象类和产品抽象类即可。无需修改原有的工厂或者产品类。
总结
这是重新学习单例模式的笔记,其中可能有很多地方写的不对,写得不好,欢迎大家指正 👏。