JS设计模式_03工厂模式·抽象工厂
技术胖
编辑于 2023年10月31日 16:50
收录于文集
共3篇

说实话,抽象工厂是我在规划课程之初,想砍掉的一节。不可否认它在强类型语言中非常有用,比如在Java和C++中就经常使用。因为这些语言在创建对象时,需要时刻关注类型之间的解耦,以便该对象日后可以表现多态性。但JavaScript是弱类型语言,就是说自带多态,所以开发中我们不考虑这部分的解耦。

你也可以发表一下你的看法,抽象工厂模式对前端到底是不是鸡肋?

我的看法是,抽象工厂对前端来说虽然用处不大,但也要学。为什么还要学习那?给你三个理由。

理由一:永远记住你是个工程师,而不只是前端切图仔,所以不要固步自封。用已知的编程语言,扩展自己的编程思想。比如你现在工作中用的TypeScript就需要这种抽象工厂模式。在不忙的时候,多学点是绝对有好处的。

理由二:面试应急,很多公司并不是那么专业。他们的技术负责人往往是后端或者全栈,所以免不了提及设计模式抽象工厂的问题。如果这时候作为一个前端,可以把抽象工厂讲的很好,可以得到很高的评价。

理由三:通过抽象工厂加深对"开放封闭原则&#​34;的理解。这个原则在你整个职业生涯中都非常有用,所以你理解越深,对你编程越好。

废话有点多了,我们直接开始正题,讲解抽象工厂模式。

开放封闭原则

可能你对开放封闭原则不太熟悉,所以我作一些介绍,如果你已经熟知,请看下一部分文章。

开放封闭原则是面向对象编程中的一个重要原则,它的基本思想是一个类只应该对外暴露它所需要的接口,而不应该暴露其内部的实现细节。

这个原则的目的是为了让类的实现细节保持私有,避免其他代码对类的内部实现进行修改。这样可以增强类的可重用性和可维护性,并且使得代码更加易于理解和调试。

在实际的编程中,开放封闭原则可以帮助我们避免一些常见的问题,如:内存泄漏、数据不一致、类型转换错误等。它也可以使得代码更加灵活和可扩展,可以方便地进行修改和升级。

抽象工厂模式

简单工厂模式从字面就可以看出,它只适合简单的业务逻辑。我们看上节课最后简单工厂的代码,可以看到如果职位很多,这个工厂函数也会无限扩大,变成屎山。

还是拿我自己举例子,生意越做越好,野心也越来越大。这时候想称霸当地的所有娱乐行业。不光想开按摩店、洗浴、还想开KTV。这时候我们的人员管理系统的编写就需要更抽象。 我们看什么是变的?什么是不变的?开这些场所都需要门面房,再加上服务人员,这些是不变的。而变的是,什么样的门面房?什么样的服务人员?我也是小白没经验,所以先写个抽象类。

代码块
JavaScript
自动换行
复制代码
class ETFactory {
  //提供场地/门市房接口
  createStore() {
    throw new Error("抽象方法,不允许直接调用,需重写。");
  }

  // 提供服务人员的接口
  createUser() {
    throw new Error("抽象方法,不允许直接调用,需重写。");
  }
}
复制成功

上面的类,只是个约定规则的类,约定了开娱乐场所的两大必要条件,地点和服务人员。这时候你说想new一个的实例,调用里边的两个方法,就会报错抛出异常(当然异常是我们自己写的)。这时候这个类就是代码最顶端的抽象了,也就是抽象工厂

抽象工厂就像大老板一样,它不干活,只享受,想动起来,还是要有具体的实践类。比如现在我们要开个按摩店,就需要写一个具体的工厂 来干活。

代码块
JavaScript
自动换行
复制代码
// 具体工厂类(实现)继承抽象工程
class AchieveFactory extends ETFactory {
  createStore() {
    //提供(返回)一个门市(地址),万达的门市
    return new WanDaStore();
  }

  createUser() {
    //返回对应的技师,SPA技师
    return new SPATechnician();
  }
}
复制成功

上面的代码我们提供了开按摩店的地点和对应的服务技师。像上面这样用来new出具体对象的类,我们一般叫做具体实现类。在工作中有抽象类,就会有具体实现类,他们都是对应出现的。

按照上面的逻辑,我们可以把门市和技师都用抽象工厂的模式去实现。先来实现门市的实体类。

代码块
JavaScript
自动换行
复制代码
class Store {
  // 门市的共性方法,这里提取了都有地址的方法
  getAddress(){
    throw new Error('抽象方法,需要重写!')
  }
}

// 万达的具体实现类
class WanDaStore extends Store{
  getAddress(){
    console.log('万达商场一楼金街88号')
  }
}

// 万象城具体实现类
class WanXiangStore extends Store{
  getAddress(){
    console.log('万象城商场二楼715号')
  }
}
复制成功

同样我们可以按照上面的方法,把技师类也抽象和具体实现出来。

代码块
JavaScript
自动换行
复制代码
// 技师的抽象类
class Technician {
  // 技师的共性方法,这里提取了技师的技能
  getSkill() {
    throw new Error("抽象方法,需要重写!");
  }
}

// SPA技师的具体实现类
class SPATechnician{
  getSkill() {
    console.log('精油SPA、恋奶推背、香薰SPA')
  }
}
// 柔式技师的具体实现类
class SoftTechnician{
  getSkill() {
    console.log('柔式按摩、躺式采耳、瑜伽按摩')
  }
}
复制成功

上面的代码写完,我们开一家红浪漫按摩店就可以用代码这样来编写:

代码块
JavaScript
自动换行
复制代码
// 我的红浪漫
const myHongLangMan = new AchieveFactory();

// 让它拥有门店
const myStore = myHongLangMan.createStore();

// 让它拥有员工
const technician = myHongLangMan.createUser();
// 得到门店地址,控制台输出--万达商场一楼金街88号
myStore.getAddress();
// 得到员工技能,控制台输出--精油SPA、恋奶推背、香薰SPA
technician.getSkill();
复制成功

好了,现在你需要注意了。这时候有一天我不想干SPA按摩店了,而是开一个柔式按摩。这时候的代码是不需要对抽象工厂ETFactory做任何修改的,只需要扩展它实现类就可以了。

代码块
JavaScript
自动换行
复制代码
// 再实现个类
class newAchieveFactory extends ETFactory {
  createStore() {
    //提供(返回)一个门市(地址)
    return new WanXiangStore();
  }

  createUser() {
    //返回对应的技师
    return new SoftTechnician();
  }
}
复制成功

这么编写代码的好处是对原有系统不会造成潜在影响,也就是所谓的“对扩展开房,对修改封闭”,是不是在抽象工厂面前非常好实现。

(如果你在学习中有任何问题、想法和疑问,或者只是单纯的想和胖哥聊聊天,都可以加我的微信,欢迎你加我,和我一起交流。微信号:php100

好了,这就是本期教程的全部内容了,内容对初学者可能不太好理解。希望你多看代码或者多看几遍视频。我是技术胖,希望我的视频对你有所帮助,也希望你能一键三连,因为这是我创作的最大动力了。我们下期视频见了。