【公众号:CS阿吉】
抽象工厂模式,属于「创建型设计模式」。
创建型设计模式是一类处理对象创建的设计模式,通过某种方式控制对象的创建来避免基本对象创建时可能导致设计上的问题或增加设计上的复杂度。
抽象工厂模式侧重于组合的扩展性,抽象工厂模式很多时候是要寻找到更好的抽象产品。
1. 定义
抽象工厂模式:提供了一个用于创建相关或相关对象族的接口,而无须指定其具体类。
抽象工厂模式实现了子类继承父类。
抽象产品的好坏才是直接决定了抽象工厂和具体工厂能否发挥最大作用的关键所在。
核心思想:生产多类产品族对象。
2. 背景
简单工厂模式是工厂去生产所有的按钮,如警告按钮、成功按钮、提醒按钮等等。
工厂方法模式是工厂去提供所有的按钮,子类工厂去生产具体的按钮,如警告按钮厂生产警告按钮,成功按钮厂生产成功按钮等等。即工厂类不再负责产品的创建,而是将具体创建工作交给子类去做。
抽象工厂模式是工厂去提供所有的产品族(如 Element UI),警告按钮可以来源于Element UI、Ant Design、Vuetify等等。之所以称Element UI为产品族,是因为Element UI不仅仅有警告按钮,还有toast提示、表单、时间线等产品。
抽象工厂模式适用于生成产品族的情景。
如果上面的表述不够生动形象,我举了个洗衣机的例子,来对比工厂模式的三个分类。
3. UML类图
4. 通用写法
Java可以使用abstract关键字来创建抽象类,但在JavaScript中abstract
是一个保留字,所以JS无法通过关键字创建抽象类,只能通过抛出异常来模拟。
抽象类:一种声明但不能使用的类,当你使用时就会报错。
abstract
在继承上有用。当你定义了一种类,并定义了该类所具备的方法,如果在子类中没有重写这些方法,那么当调用时能找到这些方法便会报错。
class AbstractFactory {
constructor() {};
makeProductA() {
throw Error('不能调用「抽象工厂类」的 makeProductA 方法');
}
makeProductB() {
throw Error('不能调用「抽象工厂类」的 makeProductB 方法');
}
}
class FactoryA extends AbstractFactory {
constructor() {
super();
}
makeProductA() {
return new ProductA1('ProductA1', 'this is ProductA1');
}
makeProductB() {
return new ProductB1('ProductB1', 'this is ProductB1');
}
}
class FactoryB extends FactoryMethod {
constructor() {
super();
}
makeProductA() {
return new ProductA2('ProductA2', 'this is ProductA2');
}
makeProductB() {
return new ProductB2('ProductB2', 'this is ProductB2');
}
}
class IProduct {
constructor(type, content) {
this.type = type;
this.content = content;
}
productCommonMethod() {
console.log('IProduct -- productCommonMethod');
}
}
class ProductA1 extends IProduct{
constructor() {
super('ProductA1', 'this is ProductA1');
}
doSpecificThing() {
console.log('ProductA1 -- doSpecificthing');
}
}
class ProductB1 extends IProduct{
constructor() {
super('ProductB1', 'this is ProductB1');
}
doSpecificThing() {
console.log('ProductB1 -- doSpecificthing');
}
}
class ProductA2 extends IProduct{
constructor() {
super('ProductA2', 'this is ProductA2');
}
doSpecificThing() {
console.log('ProductA2 -- doSpecificthing');
}
}
class ProductB2 extends IProduct{
constructor() {
super('ProductB2', 'this is ProductB2');
}
doSpecificThing() {
console.log('ProductB2 -- doSpecificthing');
}
}
在实际的代码实现中,抽象工厂模式体现为定义一个抽象工厂类,多个不同的具体工厂继承这个抽象工厂类后,再各自实现相同的抽象功能,进而实现代码上的多态性。
5. 优点
(1)可扩展性增强,容易增加新的产品系列,符合开闭原则。
(2)隔离了具体类的生成,将使用和创建的代码进行解耦。
(3)对于不同产品系列有比较多共性特征时,可以使用抽象工厂模式,有助于提升组件的复用性。
6. 缺点
(1)产品族扩展新产品困难,需修改抽象工厂的接口。
(2)增加了系统的抽象性和理解难度。
7. 应用
JS中不支持抽象化创建,所以这种模式在JS中应用不广泛。
在软件开发中,抽象工厂模式的使用场景主要就是解决跨平台兼容性的问题,比如说在 Spring 框架中的 BeanFactory。