上一篇文章我们介绍了 工厂方法模式,并用一个 ILogger 的例子展示了工厂方法模式的核心思想:暴露一个抽象的工厂方法让子类来实现,子类就可以根据自身的需求来创建不同的对象。
抽象工厂模式(Abstract Factory Pattern)也包含「工厂」的概念,但是代码实现上和工厂方法模式有较大的区别。
两者的核心区别在于:工厂方法每个工厂只负责创建一种产品,而抽象工厂一个工厂负责创建一整族相关产品,确保它们互相兼容。
实现方式上也不同:工厂方法通常依赖子类继承来重写创建方法,抽象工厂则是将工厂对象作为参数传入。
以 ILogger 的例子对比讲解一下就明白了:
工厂方法模式 中,我们实现了一个 Application 类,并暴露了一个抽象方法 createLogger(),我们实现了三个 Application 子类,分别实现 createLogger() 方法即可定制自己的日志记录器。
如果用本文介绍的抽象工厂模式来实现,需要创建一个抽象工厂接口:
// 抽象工厂接口
interface ILoggerFactory {
ILogger createLogger();
}然后实现三个具体的工厂类,每个工厂类都创建一种不同的日志记录器:
// 控制台日志具体工厂
class ConsoleLoggerFactory implements ILoggerFactory {
@Override
public ILogger createLogger() {
return new ConsoleLogger();
}
}
// 文件日志具体工厂
class FileLoggerFactory implements ILoggerFactory {
@Override
public ILogger createLogger() {
return new FileLogger("application.log");
}
}
// 远程日志具体工厂
class RemoteLoggerFactory implements ILoggerFactory {
@Override
public ILogger createLogger() {
return new RemoteLogger("http://remote-server.com");
}
}日志接口 ILogger 及其实现类 ConsoleLogger, FileLogger, RemoteLogger 和 工厂方法模式 中的实现完全相同,这里不再重复。
最后,可以这样实现我们的应用程序,只需要在构造函数中传入一个具体工厂类即可:
class Application {
private ILogger logger;
public Application(ILoggerFactory loggerFactory) {
// 通过工厂创建日志记录器
this.logger = loggerFactory.createLogger();
}
public void doSomething() {
logger.log("Start doing something...");
}
public static void main(String[] args) {
// 根据环境选择不同的工厂
ILoggerFactory loggerFactory;
String env = System.getenv("ENV");
if ("dev".equals(env)) {
loggerFactory = new ConsoleLoggerFactory();
} else if ("test".equals(env)) {
loggerFactory = new FileLoggerFactory();
} else if ("prod".equals(env)) {
loggerFactory = new RemoteLoggerFactory();
} else {
throw new IllegalArgumentException("Invalid environment: " + env);
}
// 将工厂传入应用程序
Application app = new Application(loggerFactory);
app.doSomething();
}
}上面这个简单的例子就展示了抽象工厂模式,主要有以下几个关键角色:
- 抽象产品(AbstractProduct):定义了抽象工厂所创建的对象的接口,即
ILogger接口。 - 具体产品(ConcreteProduct):实现了抽象产品接口的具体对象,即
ConsoleLogger、FileLogger和RemoteLogger类。 - 抽象工厂(AbstractFactory):抽象工厂接口,即
ILoggerFactory接口,声明了创建方法。 - 具体工厂(ConcreteFactory):实现抽象工厂接口的具体工厂类,即
ConsoleLoggerFactory、FileLoggerFactory和RemoteLoggerFactory类。
不过上述示例中,抽象工厂只有一个 createLogger 方法,过于简单了,这个场景用抽象工厂模式有些大材小用。
在实际场景中,抽象工厂通常会包含多个创建方法,用于创建一系列「相关的」对象,下面举例说明。