定义
工厂模式(Factory Pattern)属于创建型设计模式。指的是利用工厂这个媒介,提供统一的接口,从而获得对象。对于客户端而言,只需将创建对象的命令告诉工厂,具体的创建逻辑客户端是不知道的。
工厂模式可以分为两个角色:
- 工厂:只负责创建对象的逻辑,不用管其他的逻辑。
- 产品:调用工厂提供的接口,从而获取对象。
工厂模式根据不同的场景大致有三种,分别是“简单工厂”、“标准工厂”和“抽象工厂”,以下分别介绍这三种工厂模式变体。
简单工厂
简单工厂,就是最简单的一种工厂方法,利用一个静态方法,根据传递进来的参数进行判断,从而创建不同的对象。举个例子,我们希望生产一把“AK47”和一把“M4A1”。
我们需要定义一个工厂帮我们创建,我们只需要对工厂“下订单”即可。画出UML图如下,先定义一个枪支生产的接口IGun,再定义两个类“Ak47”和“M4a1”分别去实现IGun接口。最后定义一个工厂类GunFactory,在工厂类中定义一个静态方法createGun,通过客户端传递的参数type去映射,是new Ak47()呢还是new M4a1()。
客户端只需要通过GunFactory类调用静态方法,传递参数完成生产枪的指令,交给GunFactory工厂类去调度, 创建对象最终生产出想要的枪支,代码如下。
// 定义枪械的接口 interface IGun { produce(): void; // 生产枪械 } class Ak47 implements IGun { produce() { console.log('Ak47 completed!'); } } class M4a1 implements IGun { produce() { console.log('M4a1 completed!'); } } // 枪械工厂类 class GunFactory { static createGun(type: string): IGun { switch(type) { case 'ak47': return new Ak47(); case 'm4a1': return new M4a1(); default: throw new Error('type is not exist'); } } } // 客户端 不需要引入具体的产品类 通过工厂类创建具体产品 const gun1 = GunFactory.createGun('ak47'); const gun2 = GunFactory.createGun('m4a1'); gun1.produce(); // Ak47 completed! gun2.produce(); // M4a1 completed!
标准工厂
标准工厂的产生,源于简单工厂本身存在一些问题,算是对简单工厂模式的优化,一般也叫做具体工厂。我们细品代码其实可以看出,简单工厂的工厂类职责过多,强耦合;违背开闭原则,如果新增一个AWM类,则需要修改工厂类内部代码,容易对原有逻辑产生影响。
那么为了解决这个问题,针对工厂类进行解耦,将一个产品对应一个工厂,定义两个工厂“Ak47Factory”和“M4a1Factory”,分别生产“Ak47”和“M4a1”。再定义一个工厂方法,根据传入的对象执行不同产品的生产逻辑。
客户端通过创建具体的工厂对象,传给factory进行调度,使用创建出来的工厂对象调用对象内部的produce方法,从而生产出想要的枪支,代码如下。
// 定义枪械的接口 interface IGun { produce(): void; // 生产枪械 } class Ak47 implements IGun { produce(): void { console.log('Ak47 completed!'); } } class M4a1 implements IGun { produce(): void { console.log('M4a1 completed!'); } } // 定义工厂的接口 interface IFactory { createGun(): IGun; // 修改返回类型为 IGun } class Ak47Factory implements IFactory { createGun(): IGun { return new Ak47(); } } class M4a1Factory implements IFactory { createGun(): IGun { return new M4a1(); } } const factory = (factory: IFactory) => { const fac = factory.createGun(); fac.produce(); }; factory(new Ak47Factory()); // Ak47 completed! factory(new M4a1Factory()); // M4a1 completed!
对比简单工厂,标准工厂模式如果新增一个AWM,仅仅是添加AWM产品和AWM工厂,并未对之前的产品和工厂产生耦合的逻辑,虽然代码变多了,但属于线性增添是可接受的范围,最重要的是符合开闭原则。
抽象工厂
有这么一种情况,客户想要创建一系列的产品。举个例子,Ak47、M4a1、Awm这三种类型的枪支都可以做涂装,简单分为炫彩、黄金和英雄,客户想要同时生产黄金Ak47、黄金M4a1、黄金Awm。
如果使用标准工厂模式,我们经过排列组合需要创建9个工厂,随着枪支类型和涂装不断增加,我们要新建和维护的工厂呈指数级增长。那么抽象工厂的作用就体现出来了,抽象工厂无需指定类,定义一个抽象工厂AbstractFactory,具体的炫彩、黄金、英雄工厂(这里仅写了炫彩工厂)都继承抽象工厂。
定义一个客户类Client,定义一个方法produceGuns用来执行生产逻辑,这里需要传入对应的具体工厂对象,用该工厂对象调用对应的create方法。
// 抽象产品类 Ak47 M4A1 Awm abstract class Ak47 { abstract produce(): string; } abstract class M4a1 { abstract produce(): string; } abstract class Awm { abstract produce(): string; } // 具体产品 - 炫彩Ak47 class ColorfulAk47 extends Ak47 { produce(): string { return 'colorful Ak47'; } } // 具体产品 - 炫彩M4a1 class ColorfulM4a1 extends M4a1 { produce(): string { return 'colorful M4a1'; } } // 具体产品 - 炫彩Awm class ColorfulAwm extends M4a1 { produce(): string { return 'colorful Awm'; } } // 具体产品 - 黄金Ak47 class GoldAk47 extends Ak47 { produce(): string { return 'gold Ak47'; } } // 具体产品 - 黄金M4a1 class GoldM4a1 extends M4a1 { produce(): string { return 'gold M4a1'; } } // 具体产品 - 黄金Awm class GoldAwm extends Awm { produce(): string { return 'gold Awm'; } } // 具体产品 - 英雄Ak47 class HeroAk47 extends Ak47 { produce(): string { return 'hero Ak47'; } } // 具体产品 - 英雄M4a1 class HeroM4a1 extends M4a1 { produce(): string { return 'hero M4a1'; } } // 具体产品 - 英雄Awm class HeroAwm extends Awm { produce(): string { return 'hero Awm'; } } // 定义抽象工厂 abstract class AbstractFactory { abstract createAk47(): Ak47; abstract createM4a1(): M4a1; abstract createAwm(): Awm; } // 生产炫彩涂装的工厂 class ColorfulFactory extends AbstractFactory{ createAk47(): Ak47 { return new ColorfulAk47(); } createM4a1(): M4a1 { return new ColorfulM4a1(); } createAwm(): Awm { return new ColorfulAwm(); } } // 客户端类 class Client { private factory: AbstractFactory; constructor(fac: AbstractFactory) { this.factory = fac; } public produceGuns(): string { // 生产对应涂装的一套枪械 const ak47 = this.factory.createAk47(); const m4a1 = this.factory.createM4a1(); const awm = this.factory.createAwm(); return `${ak47.produce()}-${m4a1.produce()}-${awm.produce()}`; } } // 客户要生产一套炫彩枪械 const fac = new ColorfulFactory(); const client = new Client(fac); const info = client.produceGuns(); console.log(info); // colorful Ak47-colorful M4a1-colorful Awm
总结
总结一下工厂模式,首先是简单工厂是为了避免暴露创建对象具体的细节,但是存在工厂负担过重的问题,所以用标准工厂去解耦,形成一个产品一个工厂的局面;当有一组产品需要生产是引入了抽象工厂,解决群组和系列生产的问题。前端必须掌握的设计模式系列持续更新,如果对您有帮助希望多多点赞哦!