设计模式 - js 工厂模式 之 抽象工厂模式

345 阅读4分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战

在学习中有这样一段话:在学一样东西的时候,可以按照它是什么,有什么用,优点是什么,缺点是什么,要怎么去使用,或者使用的时候要注意什么。我觉得这五部曲还是很有用的,能帮你快速掌握一个知识点

前言

昨天我们介绍了工厂方法模式,以及工厂方法模式它解决了简单工厂模式的什么问题,但是它本身也存在着一些缺点:

  • 只能产生一个种类的产品。

比如会员卡就只分普通,白银,黄金会员卡,优惠卷就只分九折优惠卷,八折优惠卷和七折优惠卷,我没办法让一个产生会员卡的工厂去帮我生产优惠卷,但是在现实中应该是有一个综合性的大工厂,他会生产优惠卷,在需要的时候又能够为你办理会员卡。

而抽象工厂的出现,就解决了这个问题,抽象工厂将多个类似的产品定义为一个产品族系,可以称它为:工厂的工厂

抽象工厂模式是什么

是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

简单来说抽象工厂就是工厂方法的升级,工厂方法只能产生一个种类的产品,而抽象工厂能产生多个种类的产品。

结合之前的两种模式,简单工厂模式产生实例,工厂方法模式产生实例的接口,而抽象工厂模式产生的是工厂,可以结合下图做一个理解。

image.png

抽象工厂模式的优点

抽象工厂模式除了拥有工厂方法模式所以的优点外,还有下面的优点:

  • 加强可扩展性。抽象工厂增强了程序的可扩展性,当增加一个新的产品类时,不需要修改原代码,满足开闭原则。

抽象工厂模式的缺点

  • 系统复杂度提升。由于抽象工厂模式是工厂方法模式的扩展,所以在工厂方法模式的基础上变得更为复杂了。

  • 增加修改的难度。一旦出现产品的实现需要修改,那么就可能牵扯到三个类的代码修改,这反而有点违背了编码的原则。

抽象工厂模式的使用

由于抽象工厂模式并不是直接产生实例的,而是产生工厂,我们还是可以像昨天一样使用 new.target 来模仿抽象类,并且通过继承抽象工厂创建出一系列的子类工厂,最后我们还需要定义一个方法,用于创建我们想要的子类工厂的实例。

new.target - JavaScript | MDN (mozilla.org)

class PreferentialCenter {
  constructor(type) {
    if (new.target === PreferentialCenter) {
      throw new Error("抽象类不能实例化!");
    }
    this.type = type;
  }
}

class Coupon extends PreferentialCenter {
  constructor(opt) {
    super("Coupon");
    this.name = (opt && opt.name) || "";
    this.calculate = (price) => {
      return price * 0.9;
    };
  }
}

class Card extends PreferentialCenter {
  constructor(name) {
    super("Card");
    this.name = name || "";
    this.calculate = (price) => {
      return price * 0.8;
    };
  }
}

class Fullminus extends PreferentialCenter {
  constructor(name) {
    super("Fullminus");
    this.name = name || "";
    this.calculate = (price) => {
      return price > 10 ? price - 5 : price;
    };
  }
}

function getPreferentialCenterFactory(type) {
  switch (type) {
    case "Coupon":
      return Coupon;
      break;
    case "Card":
      return Card;
      break;
    case "Fullminus":
      return Fullminus;
      break;
    default:
      throw new Error("参数错误, 可选参数:Coupon, Card, Fullminus");
  }
}

let CouponCenter = getPreferentialCenterFactory("Coupon");
let CardCenter = getPreferentialCenterFactory("Card");
let FullminusCenter = getPreferentialCenterFactory("Fullminus");

let coupon = new CouponCenter("优惠卷");
console.log(coupon.calculate(100)); //90

let card = new CardCenter("会员卡");
console.log(card.calculate(100)); //80

let fullminus = new FullminusCenter("满减");
console.log(fullminus.calculate(100)); //95


以上就是一个简单的抽象工厂模式,相比较于工厂方法模式,抽象工厂虽然更加的复杂,但是可以支持创建更多不同类别的子类工厂,主要用于大型项目的设计当中。

总结

三种工厂模式就已经都介绍了一遍,三种模式都有着自己的优点和缺点,具体的使用需要根据具体的项目来确定,选择合适的工厂模式能够让复杂的创建变得简单起来,也能够方便之后的系统维护。