在现实生活中,工厂是负责生产产品的,比如牛奶、面包或礼物等,这些产品满足了我们日常的生理需求。此外,在日常生活中,我们也离不开大大小小的系统,这些系统是由不同的组件对象构成。(文末有送书福利,对 Node.js 和 Vue.js 感兴趣的小伙伴不要错过哟)

作为一名 Web 软件开发工程师,在软件系统的设计与开发过程中,我们可以利用设计模式来提高代码的可重用性、可扩展性和可维护性。在众多设计模式当中,有一种被称为工厂模式的设计模式,它提供了创建对象的最佳方式。

Typescript 设计模式之工厂方法_闲谈

工厂模式可以分为三类:

  • 简单工厂模式(Simple Factory Pattern)
  • 工厂方法模式(Factory Method Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)

本文阿宝哥将介绍简单工厂模式与工厂方法模式,而抽象工厂模式将在后续的文章中介绍,下面我们先来介绍简单工厂模式。

一、简单工厂模式

1.1 简单工厂模式简介

简单工厂模式又叫 静态方法模式,因为工厂类中定义了一个静态方法用于创建对象。简单工厂让使用者不用知道具体的参数就可以创建出所需的 ”产品“ 类,即使用者可以直接消费产品而不需要知道产品的具体生产细节。

相信对于刚接触简单工厂模式的小伙伴来说,看到以上的描述可能会觉得有点抽象。这里为了让小伙伴更好地理解简单工厂模式,阿宝哥以用户买车为例,来介绍一下 BMW 工厂如何使用简单工厂模式来生产????。

Typescript 设计模式之工厂方法_闲谈_02

在上图中,阿宝哥模拟了用户购车的流程,pingan 和 qhw 分别向 BMW 工厂订购了 BMW730 和 BMW840 型号的车型,接着工厂按照对应的模型进行生产并在生产完成后交付给用户。接下来,阿宝哥将介绍如何使用简单工厂来描述 BMW 工厂生产指定型号车子的过程。

1.2 简单工厂模式实战

Typescript 设计模式之工厂方法_闲谈_03
  1. 定义 BMW 抽象类
abstract class BMW {  abstract run(): void;}
  1. 创建 BMW730 类(BMW 730 Model)
class BMW730 extends BMW {  run(): void {    console.log("BMW730 发动咯");  }}
  1. 创建 BMW840 类(BMW 840 Model)
class BMW840 extends BMW {  run(): void {    console.log("BMW840 发动咯");  }}
  1. 创建 BMWFactory 工厂类
class BMWFactory {  public static produceBMW(model: "730" | "840"): BMW {    if (model === "730") {      return new BMW730();    } else {      return new BMW840();    }  }}
  1. 生产并发动 BMW730 和 BMW840
const bmw730 = BMWFactory.produceBMW("730");const bmw840 = BMWFactory.produceBMW("840");
bmw730.run();bmw840.run();

以上代码运行后的输出结果为:

BMW730 发动咯 BMW840 发动咯

通过观察以上的输出结果,我们可以知道我们的 BMWFactory 已经可以正常工作了。在 BMWFactory 类中,阿宝哥定义了一个 produceBMW() 方法,该方法会根据传入的模型参数来创建不同型号的车子。

看完简单工厂模式实战的示例,你是不是觉得简单工厂模式还是挺好理解的。那么什么场景下使用简单工厂模式呢?要回答这个问题我们需要来了解一下简单工厂的优缺点。

1.3 简单工厂模式优缺点

1.3.1 优点
  • 将创建实例与使用实例的任务分开,使用者不必关心对象是如何创建的,实现了系统的解耦;
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可。
1.3.2 缺点
  • 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,也有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。

了解完简单工厂的优缺点,我们来看一下它的应用场景。

1.4 简单工厂模式应用场景

在满足以下条件下可以考虑使用简单工厂模式:

  • 工厂类负责创建的对象比较少:由于创建的对象比较少,不会造成工厂方法中业务逻辑过于复杂。
  • 客户端只需知道传入工厂类静态方法的参数,而不需要关心创建对象的细节。

介绍完简单工厂模式,接下来我们来介绍本文的主角 ”工厂方法模式“

二、工厂方法模式

2.1 工厂方法简介

工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫多态工厂(Polymorphic Factory)模式,它属于类创建型模式。

在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象, 这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

Typescript 设计模式之工厂方法_闲谈_04

在上图中,阿宝哥模拟了用户购车的流程,pingan 和 qhw 分别向 BMW 730 和 BMW 840 工厂订购了 BMW730 和 BMW840 型号的车型,接着工厂按照对应的模型进行生产并在生产完成后交付给用户。接下来,阿宝哥来介绍如何使用工厂方法来描述 BMW 工厂生产指定型号车子的过程。

2.2 工厂方法实战

Typescript 设计模式之工厂方法_闲谈_05
  1. 定义 BMW 抽象类
abstract class BMW {  abstract run(): void;}
  1. 创建 BMW730 类(BMW 730 Model)
class BMW730 extends BMW {  run(): void {    console.log("BMW730 发动咯");  }}
  1. 创建 BMW840 类(BMW 840 Model)
class BMW840 extends BMW {  run(): void {    console.log("BMW840 发动咯");  }}
  1. 定义 BMWFactory 接口
interface BMWFactory {  produceBMW(): BMW;}
  1. 创建 BMW730Factory 类
class BMW730Factory implements BMWFactory {  produceBMW(): BMW {    return new BMW730();  }}
  1. 创建 BMW840Factory 类
class BMW840Factory implements BMWFactory {  produceBMW(): BMW {    return new BMW840();  }}
  1. 生产并发动 BMW730 和 BMW840
const bmw730Factory = new BMW730Factory();const bmw840Factory = new BMW840Factory();
const bmw730 = bmw730Factory.produceBMW();const bmw840 = bmw840Factory.produceBMW();
bmw730.run();bmw840.run();

通过观察以上的输出结果,我们可以知道我们的 BMW730Factory 和 BMW840Factory 工厂已经可以正常工作了。相比前面的简单工厂模式,工厂方法模式通过创建不同的工厂来生产不同的产品。下面我们来看一下工厂方法有哪些优缺点。

2.3 工厂方法优缺点

2.3.1 优点
  • 在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,更加符合 “开闭原则”。而简单工厂模式需要修改工厂类的判断逻辑。
  • 符合单一职责的原则,即每个具体工厂类只负责创建对应的产品。而简单工厂模式中的工厂类存在一定的逻辑判断。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
2.3.2 缺点
  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  • 一个具体工厂只能创建一种具体产品。

最后我们来简单介绍一下工厂方法的应用场景。

2.4 工厂方法应用场景

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

三、参考资源

  • 简单工厂模式(SimpleFactoryPattern)
  • design-patterns - simple_factory
  • 工厂方法模式(Factory Method)

四、文末送书

Typescript 设计模式之工厂方法_闲谈_06

快速上手:采用Node.js中流行的Express框架进行项目开发,方便快捷

技术新颖:不仅介绍传统的后端渲染架构,还介绍新近流行的前后端分离架构

注重实战:详解3个完整的商业项目案例开发中的需求分析、架构设计和代码编写

新颖独特:介绍了一种基于Express框架搭建的文件目录结构,提高项目开发效率

4.1 抽奖送书

抽奖方式很简单,扫码下面二维码关注 全栈修仙之路,然后在后台回复 “8”

Typescript 设计模式之工厂方法_闲谈_07

活动礼品:Node.js+Express+Vue.js 项目开发实战,共个名额;

开奖时间:2020 年 08 月 14 日 18:00;

活动说明:为了把书送给更多粉丝,同一人只能参与一次,同一微信号/手机号/收货人视为同一个人。

4.2 留言送书

分享你学习 Node.js 或 Vue.js 的心得 ,开奖后点赞数第 1 名的即为中奖者,大家加油。

另外,对于中奖的幸运小伙伴,如果在 开奖前 添加阿宝哥为微信好友,中奖后阿宝哥再发一个 6.66 的红包???? 哟。

Typescript 设计模式之工厂方法_闲谈_08

最后,祝大家好运。注意上述送书活动的中奖者请于 3 天内联系阿宝哥兑奖,逾期无效。再次感谢 机械工业出版社 对本次活动的大力支持????。

▼推荐阅读▼ TypeScript 设计模式之适配器模式

TypeScript 设计模式之适配器模式

 TypeScript 设计模式之模板方法

TypeScript 设计模式之模板方法

 TypeScript 设计模式之享元模式

TypeScript 设计模式之享元模式

聚焦全栈,专注分享 TypeScript、Web API、Deno 等技术干货。

Typescript 设计模式之工厂方法_闲谈_09