抽象工厂模式提供一个创建一组相关或相互依赖的对象 的接口,而无须指定它们具体的类,每个子类可以生产一系列相关的产品。
text
The Abstract Factory Pattern is to provide an interface for creating families of related or dependent objects
without specifying their concrete classes.
结构设计
抽象工厂模式包含如下角色:
AbstractFactory,抽象工厂,负责声明一组产品创建的工厂方法 ,每个方法返回一个AbstractProduct类型的对象。
ConcreteFactory,具体工厂,用来实现AbstractFactory声明的工厂方法,以创建具有特定实现的产品对象。
AbstractProduct,抽象产品,用来声明一组不同但相关的产品声明的接口 。
ConcreteProduct,具体产品,用来实现AbstractProduct的接口,以定义特定的产品。
抽象工厂模式类图表示如下:
伪代码实现
接下来将使用代码介绍下抽象工厂模式的实现。
(1) 定义一组产品(ProductA、ProductB、...)抽象类(也可以是基类),对产品接口进行声明。然后定义具体产品(Concrete Products),实现产品声明的接口。
java
public abstract class ProductA {
abstract void function();
}
public class ConcreteProductA1 extends ProductA {
@Override
public void function() {
System.out.println("---------do some thing in a ConcreteProductA1 instance---------");
}
}
public class ConcreteProductA2 extends ProductA {
@Override
public void function() {
System.out.println("---------do some thing in a ConcreteProductA2 instance---------");
}
}
public abstract class ProductB {
abstract void foo();
}
public class ConcreteProductB1 extends ProductB {
@Override
public void foo() {
System.out.println("---------do some thing in a ConcreteProductB1 instance---------");
}
}
public class ConcreteProductB2 extends ProductB {
@Override
public void foo() {
System.out.println("---------do some thing in a ConcreteProductB2 instance---------");
}
}
(2) 定义产品工厂(Product Factory)抽象类或基类,声明返回一组产品对象的工厂方法。每个方法的返回对象类型必须与产品接口相匹配。然后定义具体产品工厂(Concrete Product Factories)重写基础工厂方法, 使其返回不同类型的产品。
java
public abstract class ProductFactory {
/**
* 生产产品A
*/
abstract ProductA createProductA();
/**
* 生产产品B
*/
abstract ProductB createProductB();
}
public class ProductFactory1 extends ProductFactory {
@Override
public ProductA createProductA() {
System.out.println("create ProductA");
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
System.out.println("create ProductB");
return new ConcreteProductB1();
}
}
public class ProductFactory2 extends ProductFactory {
@Override
public ProductA createProductA() {
System.out.println("create ProductB");
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
System.out.println("create ProductB");
return new ConcreteProductB2();
}
}
(3) 客户端调用。支持多种调用方式,如:直接在方法中实例化工厂子类、提供静态方法,支持方法参数中传递工厂对象、提供对象方法,使用构造函数中传入的工厂对象。
java
public class AbstractFactoryClient {
private ProductFactory factory;
public AbstractFactoryClient(ProductFactory factory) {
this.factory = factory;
}
// 调用方式一:方法中实例化工厂子类
public void test() {
// (1) 实例化产品工厂
ProductFactory productFactory1 = new ProductFactory1();
// (2) 生产产品
ProductA productA1 = productFactory1.createProductA();
// (3) 使用产品
productA1.function();
// 下同
ProductB productB1 = productFactory1.createProductB();
productB1.foo();
ProductFactory productFactory2 = new ProductFactory2();
ProductA productA2 = productFactory2.createProductA();
productA2.function();
ProductB productB2 = productFactory2.createProductB();
productB2.foo();
}
// 调用方式二:工厂对象作为方法参数(工具类方法)
public static void foo(ProductFactory factory) {
ProductA productA1 = factory.createProductA();
productA1.function();
ProductB productB1 = factory.createProductB();
productB1.foo();
}
// 调用方式三:使用构造函数中传入的工厂(工厂一旦绑定,无法修改)
public void foo() {
ProductA productA1 = this.factory.createProductA();
productA1.function();
ProductB productB1 = this.factory.createProductB();
productB1.foo();
}
}
适用场景
在以下情况下可以考虑使用抽象工厂模式:
(1) 如果需要与多个不同系列的相关产品交互,但无法预知对象确切类别及其依赖关系时,可使用抽象工厂。
抽象工厂将创建产品的代码与实际使用产品的代码分离,从而能在不影响其他代码的情况下扩展产品创建部分代码。
(2) 如果希望用户能扩展软件库或框架的内部组件,可使用抽象工厂。
继承是扩展软件库或框架默认行为的最简单方法 。但是,当使用子类替代标准组件时,框架如何辨识出该子类?解决方案是将各框架中构造组件的代码集中到单个工厂方法中,并在继承该组件之外允许任何人对该方法进行重写。
(3) 如果存在一个基于一组抽象方法的类,且其主要功能因此变得不明确,可使用抽象工厂。
在设计良好的程序中, 每个类仅负责一件事。如果一个类与多种类型产品交互,就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。
优缺点
抽象工厂模式有以下优点:
(1) 将创建产品的代码与实际使用产品的代码分离(解耦),避免产品创建工厂和实际产品之间的紧耦合。
(2) 单一职责原则。产品创建代码放在单独的类里,从而使得代码更容易维护。
(3)开闭原则。无需更改客户端调用代码, 就可以在程序中引入新的产品类型。
但是抽象工厂模式也存在以下缺点:
(1) 应用抽象工厂模式需要引入许多新的子类,代码会因此变得更复杂。最好的情况是将该模式引入产品类的现有层次结构中(将工厂类组合到产品类里)。
(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到反射等技术,增加了系统的实现难度。
参考
https://www.edrawsoft.cn/ 亿图图示
《设计模式:可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著 李英军, 马晓星 等译
https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/abstract_factory.html 抽象工厂模式
https://refactoringguru.cn/design-patterns/abstract-factory 抽象工厂模式
https://blog.csdn.net/ShuSheng0007/article/details/86644481 秒懂设计模式之抽象工厂模式
https://www.cnblogs.com/adamjwh/p/9033552.html 简说设计模式------抽象工厂模式