标签: 前端 设计模式 工厂模式 typescript factory
如果下面的代码你能轻易阅读,那么你已经熟悉工厂模式,可以接着学习其他的设计模式。
factory.jpg
工厂模式:一个类或对象中往往会包含别的对象,在创建这种成员对象时。我们经常使用new来创建,但是这会导致相关的两个类之间产生依赖性。工厂模式使用了一个方法来决定使用究竟实例哪个类。
简单工厂
工厂模式,即类似于工厂一样有一个流程化的形式。
比方说服装厂,先是任意一种服装的制作,然后是漂洗,最后是包装出场。
写成代码如下所示。
/* simple-factory.ts */
import CloseTypeEnum from './close-type-enum';
class SimpleFactory {
private static _instance: SimpleFactory;
public static get instance() {
if (!this._instance) {
this._instance = new SimpleFactory();
}
return this._instance;
}
public createClose(closeType: CloseTypeEnum): string {
let closeName: string = null;
switch (closeType) {
case CloseTypeEnum.Sweater:
closeName = 'sweater';
break;
case CloseTypeEnum.Shirt:
closeName = 'shirt';
break;
case CloseTypeEnum.Jacket:
closeName = 'jacket';
break;
default :
throw new Error('can\'t find type' + closeType);
}
this.washingsClose(closeName);
this.packagingClose(closeName);
return closeName;
}
public washingsClose(close: string) {}
public packagingClose(close: string) {}
}
用一个类来创建经过一系列流程对象,对象的创建和流程解除依赖。从而解除依赖,更容易增加对象种类。便于以后维护和扩展。
抽象工厂
如上面的服装厂的流程,我们的服装厂要增加一种衣服的类型时,仍然需要进入工厂类中增加一个case。如果每一个case里面的流程是非常复杂的,那我们用switch case显然是不合适的。
这时候我们需要用到抽象工厂。
将生产衣服的这个switch case抽象成一个接口,因为我们只关心最终造出来的衣服,而不关心制作的流程。
换成代码就是写几个方法都去实现makeClose的接口。
/* i-factory-interface.ts */
interface ICloseMakerFactory {
makeClose(): IClose
}
interface IClose {
name: string
price: number
note: string
}
export {
ICloseMakerFactory,
IClose,
};
/* sweater-producer.ts */
import { IClose, ICloseMakerFactory } from '../i-factory-interface';
export default class SweaterProducer implements ICloseMakerFactory {
makeClose(): IClose {
return {
name: 'sweater',
price: 15,
note: 'The process can be complex',
};
}
}
/* shirt-producer.ts */
import { IClose, ICloseMakerFactory } from '../i-factory-interface';
export default class ShirtProducer implements ICloseMakerFactory {
makeClose(): IClose {
return {
name: 'shirt',
price: 20,
note: 'The process can be complex',
};
}
}
**/* jacket-producer.ts */
import { IClose, ICloseMakerFactory } from '../i-factory-interface';
export default class JacketProducer implements ICloseMakerFactory {
makeClose(): IClose {
return {
name: 'jacket',
price: 25,
note: 'The process can be complex',
};
}
}**
然后在主方法中调用这些方法去实现生产衣服的过程。
class AbstractFactory {
private static _instance: AbstractFactory;
private closeTypeAnalyzerMapping: Map<CloseTypeEnum, ICloseMakerFactory>;
constructor() {
this.closeTypeAnalyzerMapping.set(CloseTypeEnum.Jacket, new JacketProducer());
this.closeTypeAnalyzerMapping.set(CloseTypeEnum.Shirt, new ShirtProducer());
this.closeTypeAnalyzerMapping.set(CloseTypeEnum.Sweater, new SweaterProducer());
}
public static get instance() {
if (!this._instance) {
this._instance = new AbstractFactory();
}
return this._instance;
}
public makeCloseTypeAnalyzer(type: CloseTypeEnum): ICloseMakerFactory {
if (this.closeTypeAnalyzerMapping.has(type)) {
return this.closeTypeAnalyzerMapping.get(type);
} else {
throw new Error('our factory don\'t have this type');
}
}
}
const shrit= AbstractFactory.instance.makeCloseTypeAnalyzer(CloseTypeEnum.Shirt).makeClose();
当然,实际场景中过程的每一步都会根据衣服的种类有多种实现方法,我们可以按照生产衣服一样将他们区分开来。
这样,未来我们增加了一种衣服的类型或者洗涤方法等,只需要增加一个实现类而不用大面积的改变主方法。
工厂模式的利弊
利:
-
消除对象间的耦合:
使用工厂方法而不是new关键字,解除创建过程中的耦合步骤,增加可维护性和可测试性。 -
易于模块化
使用工厂模式,可以先创建一个抽象的父类,然后在子类中创建工厂方法,从而把成员对象的实例化推迟到更专门的子类中进行。增加可拓展性。
弊:
工厂模式在处理多流程或者是根据上下文创建实例的情况下非常好用。但是在单一流程或者是不需要根据上下文创建对象的情况下使用反而会增加阅读成本。
所以我们应该在恰当的场景中使用工厂模式。如果拿不定主意,那就不要使用,因为在以后的重构中还有机会使用工厂模式。