【公众号:CS阿吉】

D 003 工厂方法模式(Factory Method)_设计模式

 

工厂方法模式,又称为工厂模式,属于「创建型设计模式」。

它是简单工厂模式的升级版,解决了简单工厂模式违背开闭原则的问题。

工厂方法模式侧重于继承的连续性,工厂方法模式会更多去关注是否满足里氏替换原则。

创建型设计模式是一类处理对象创建的设计模式,通过某种方式控制对象的创建来避免基本对象创建时可能导致设计上的问题或增加设计上的复杂度。

1. 定义

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

它将产品的实例化延迟到工厂类的子类中完成。 主要解决「产品扩展」问题。

核心思想:创建多类对象。

2. 背景

简单工厂模式是工厂去生产所有的按钮,如警告按钮、成功按钮、提醒按钮等等。

工厂方法模式是工厂去提供所有的按钮,子类工厂去生产具体的按钮,如警告按钮厂生产警告按钮,成功按钮厂生产成功按钮等等。即工厂类不再负责产品的创建,而是将具体创建工作交给子类去做。

工厂方法模式可在不修改工厂类的情况下,引入新产品,即符合开闭原则。

3. UML类图

D 003 工厂方法模式(Factory Method)_工厂类_02

4. 通用写法

class FactoryMethod {
constructor() {};
makeProduct() {}
}

class FactoryA extends FactoryMethod {
constructor() {
super();
}

makeProduct() {
return new ProductA('ProductA', 'this is ProductA');
}
}

class FactoryB extends FactoryMethod {
constructor() {
super();
}

makeProduct() {
return new ProductB('ProductB', 'this is ProductB');
}
}

class FactoryC extends FactoryMethod {
constructor() {
super();
}

makeProduct() {
return new ProductC('ProductC', 'this is ProductC');
}
}

class IProduct {
constructor(type, content) {
this.type = type;
this.content = content;
}

productCommonMethod() {
console.log('IProduct -- productCommonMethod');
}
}

class ProductA extends IProduct{
constructor() {
super('ProductA', 'this is ProductA');
}
doSpecificThing() {
console.log('ProductA -- doSpecificthing');
}
}

class ProductB extends IProduct{
constructor() {
super('ProductB', 'this is ProductB');
}
doSpecificThing() {
console.log('ProductB -- doSpecificthing');
}
}

class ProductC extends IProduct{
constructor() {
super('ProductC', 'this is ProductC');
}
doSpecificThing() {
console.log('ProductC -- doSpecificthing');
}
}

let a = new FactoryA();
a.makeProduct().doSpecificThing();
let b = new FactoryB();
b.makeProduct().doSpecificThing();
let c = new FactoryA();
c.makeProduct().doSpecificThing();

5. 优点

(1)符合开闭原则

(2)符合单一职责原则

(3)统一管理创建对象的不同实现逻辑,扩展性高,新产品只需要多写一个具体工厂类即可。

(4)经典的解耦框架,降低代码耦合性。高层模块只需要知道产品的抽象类,无需关心其他类,满足依赖倒置原则、迪米特法则、里氏替换原则。

依赖倒置原则:高层模块不依赖于底层模块。 迪米特法则:一个对象应该对其他对象保持最少的了解,不知道的不要知道。 里氏替换原则:子类重写方法功能发生改变,不应该影响父类方法的含义。

6. 缺点

(1)类的个数增加时,增加复杂度。

(2)抽象层提高了扩展性,同时也增加了理解难度。

(3)抽象产品只能生产一种产品,此弊端可使用「抽象工厂模式」解决。

7. 应用

7-1. React createElement

// createElement() 
export function createElement(type, config, children) {
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;

// 处理children,全部挂载到props的children属性上
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
props.children = childArray;
}

// 生成虚拟DOM
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}