介绍

工厂模式 是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。

场景

假如我们开发项目中的日志模块,业务初期只有控制台日志,大部分代码都在控制台日志类。随着业务发展,希望可以增加文件日志功能。

如果代码之间已经存在耦合关系,此时向程序添加新类并不是一件简单的事情。目前大部分代码都与控制台日志类有关。添加文件日志类需要修改全部代码,更可怕的是以后万一要拓展其他日志类,很可能需要再次大幅修改代码。

如此反复反复,恭喜, 成功诞生一份不可维护的祖传代码。 😂

解决方案

工厂方法模式建议使用特殊的工厂方法代替直接调用 new 关键字创建对象。工厂方法返回的对象通常被称作 “产品”。

1
2
3
public abstract class Logger {
public abstract void log();
}
1
2
3
4
5
6
7
public class ConsoleLogger extends Logger {

@Override
public void log() {
System.out.println("我是控制台日志器!");
}
}
1
2
3
4
5
6
7
public class FileLogger extends Logger {

@Override
public void log() {
System.out.println("我是文件日志器!");
}
}

紧接着我们再创建一个工厂类,这里声明为抽象类,并且设置一个抽象方法,强制子类实现抽象方法。你也可以不设置成抽象类,在基础工厂方法中返回默认类型。

1
2
3
public abstract class LoggerFactory {
public abstract Logger createLogger();
}
1
2
3
4
5
6
7
public class ConsoleLoggerFactory extends LoggerFactory {

@Override
public Logger createLogger() {
return new ConsoleLogger();
}
}
1
2
3
4
5
6
7
public class FileLoggerFactory extends LoggerFactory {

@Override
public Logger createLogger() {
return new FileLogger();
}
}

img

乍看之下,工厂模式看起来毫无意义,只是改变了程序中调用构造函数的位置而已。但是我们可以在子类里重写工厂方法,从而改变其创建产品的类型。

但有一点需要注意,仅当这些产品具有共同的父类或者接口时,工厂子类才能返回不同类型的产品。同时工厂基类的工厂方法还应将其返回类型声明为共有接口。

只要产品类实现一个共同的接口,就可以将它传递给客户代码,而无需提供任何额外的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Application {

private final LoggerFactory loggerFactory;

public Application(LoggerFactory loggerFactory) {
this.loggerFactory = loggerFactory;
}

public void run() {
Logger logger = loggerFactory.createLogger();
logger.log();
}
}

客户端代码仅通过抽象类型使用工厂和产品,如需要添加新的产品,仅需实现工厂抽象类和产品抽象类即可。无需修改原有的工厂或者产品类。

总结

这是重新学习工厂模式的笔记,其中可能有很多地方写的不对,写得不好,欢迎大家指正 👏