admin管理员组

文章数量:1441365

JavaScript版本的23种常用设计模式快速入门教程

一、简介

读者请注意本文是基于前端脚本语言JavaScript(JavaScript 1.6和ES6)来编写的设计模式教程,若是后端语言读者请移到扩展阅读部分选择相应语言查阅

扩展阅读

常用设计模式UML图示

Java版本设计快速入门(基于常用电商平台业务-订单、支付、购物车、优惠券、商品、店铺来编写实践示例)

Golang(基于常用电商平台业务-订单、支付、购物车、优惠券、商品、店铺来编写实践示例)

Python (基于常用电商平台业务-订单、支付、购物车、优惠券、商品、店铺来编写实践示例)

C++(基于常用电商平台业务-订单、支付、购物车、优惠券、商品、店铺来编写实践示例)

1.设计模式定义

设计模式是一组有用的解决方案,用于解决特定类型的软件设计问题。它们通常提供了一种抽象出来的方式,来表达应用程序中常见问题的解决方案,从而帮助开发者更有效地解决问题。设计模式的用途是帮助开发者解决软件设计问题,提高开发效率,降低开发成本,提高代码质量和可维护性,以及更好地管理和理解复杂的系统。设计模式的优点是可以提高代码可维护性,减少代码重复,提高开发效率,降低开发成本,提高代码质量和可维护性,以及更好地管理和理解复杂的系统。设计模式的缺点是可能会使代码变得复杂,也可能会过度设计。设计模式的出处是由GoF(Gang of Four)在1995年发表的著作“设计模式:可复用面向对象软件的基础”中提出。

2.设计模式的历史

设计模式可以追溯到1960年代,当时著名的软件工程师和设计师们开始研究如何提高软件开发的效率和可维护性。他们发现,应用一些重复出现的设计模式可以提高软件开发的效率,并极大地改善软件的可读性和可维护性。这些设计模式在1970年代末被称为“永恒的设计模式”,并在1995年由Erich Gamma,Richard Helm, Ralph Johnson和John Vlissides出版。他们的书,称为“设计模式:可复用面向对象软件的基础”,成为设计模式的代表作品,并且引发了关于设计模式的热烈讨论。此外,这本书还为软件开发人员提供了一套可复用的设计模式,以帮助他们更好地理解和实施设计模式

二、设计模式的六大原则

总原则:开闭原则(Open Close Principle)

实体应该对扩展开放,对修改关闭,即软件实体应尽量在不修改原有代码的情况下进行扩展。

应用时注意点是要充分利用抽象类和接口、多态等特性,将可变部分封装起来,提高系统的灵活性和可维护性。

1、单一职责原则

一个类应该只负责一项职责,不要存在多于一个的非本职责原因引起类的变更。简单来说就是类的职责要单一。

应用时注意点是要在设计时尽量把类的职责划分清楚,把功能模块化,提高系统的灵活性和可维护性。

2、里氏替换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

历史替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。

应用时注意点是在设计时应让父类和子类之间有一个共同的抽象层,以便子类可以重写父类的抽象方法,并在子类中实现这些抽象方法。

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。

应用时注意点是要在设计时以抽象为基础,尽量将细节层次降低,使系统可以更灵活地应对变化。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

4、接口隔离原则(Interface Segregation Principle)

每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。简单地说使用多个专门的接口,而不使用单一的总接口。

应用时注意点是要把接口进行分解,使用多个小接口,以便更好地实现功能的模块化管理,提高系统的灵活性和可维护性。

5、迪米特法则(最少知道原则)(Demeter Principle)

就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。

最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。

应用时注意点是要尽量减少类与类之间的耦合,提高系统的灵活性和可维护性。

6、合成复用原则(Composite Reuse Principle)

指尽量使用组合/聚合的方式,而不是使用继承关系来达到复用的目的。

应用时注意点是要尽量使用组合/聚合的方式,使用继承可能带来的耦合性太强,从而影响系统的灵活性和可维护性。

二、设计模式的分类

总体来说设计模式分为三大类:

创建型设计模式,共五种:工厂方法设计模式、抽象工厂设计模式、单例设计模式、建造者设计模式、原型设计模式。

结构型设计模式,共七种:适配器设计模式、装饰器设计模式、代理设计模式、外观设计模式、桥接设计模式、组合设计模式、享元设计模式。

行为型设计模式,共十一种:策略设计模式、模板方法设计模式、观察者设计模式、迭代子设计模式、责任链设计模式、命令设计模式、备忘录设计模式、状态设计模式、访问者设计模式、中介者设计模式、解释器设计模式。

1. 工厂方法设计模式(Factory Method Pattern)

定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。

它的思想是:在工厂设计模式中,我们创建对象不是直接使用 new 关键字创建,而是将创建对象的行为委托给另一个类,也就是工厂类。把实例化的步骤抽象出来,让子类决定实例化哪一个类。

应用场景:当一个类不知道它所必须创建的对象的类的时候,或者根据不同条件创建不同实例时,可以使用工厂设计模式。

2. 抽象工厂设计模式(Abstract Factory Pattern)

抽象工厂设计模式是一种创建型设计模式,它提供一种方法创建一组相关的产品,而无需指定它们的具体类。

优点:具体产品类的实现细节完全隐藏,不需要关心创建细节;增加新的具体产品类只需要添加一个新的具体产品类和相应的具体工厂类,不会影响已有系统;符合“开放-封闭”原则。

缺点:增加新的产品类比较困难,需要修改抽象工厂和所有的具体工厂类。

3.单例设计模式(Singleton Pattern)

单例设计模式是一种常用的软件设计模式,指的是在一个类里面有一个私有构造函数和一个公开静态方法,这个方法返回对象的唯一实例。

单例设计模式的应用场景是:需要一个只能创建一个实例的类,如 配置类、日志类、计数器类等。

优点:降低内存开销;确保全局唯一;可以控制实例数量。

缺点:不支持继承;不灵活;与单一职责原则冲突。

4.建造者设计模式(Builder Pattern)

建造者设计模式是一种创建型设计模式,它使用抽象的建造者来构建一个复杂的对象。

它的思想是:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者设计模式的应用场景是:当创建一个复杂的对象时,可以使用建造者设计模式来将复杂对象的创建过程与它的表示进行分离,从而使得构建过程更加清晰。

优点:构建和表示分离;良好的封装性;可以构造复杂的对象。

缺点:难以控制产品的组成部分;产品的组成部分太多,可能会出现很多具体的建造者类。

5.原型设计模式

原型设计模式是一种创建型设计模式,它使用一个原型对象来创建新的对象。

它的思想是:通过复制一个已经存在的实例来创建新的实例,而不是通过new关键字来创建新的实例。

原型设计模式的应用场景是:当类的创建开销比较大或者构造函数中需要复杂操作时,原型设计模式可以派上用场。

优点:性能优良;简化创建过程;灵活性高。

缺点:配备克隆方法需要对类的功能进行较大的改造,这是非常有风险的改动;必须实现Cloneable接口;使用原型设计模式时,不能使用final类型。

6.适配器设计模式(Adapter Pattern)

适配器设计模式是一种结构型设计模式,它将一个类的接口转换成客户希望的另一个接口。

它的思想是:将一个类的接口转换成客户希望的另一个接口,从而使原本接口不兼容的类可以一起工作。

适配器设计模式的应用场景是:当你希望使用一个已经存在的类,但是它的接口与你的要求不匹配时,可以使用适配器设计模式来解决这个问题。

优点:提高了类的复用性;增加了类的透明度;灵活性高。

缺点:增加了系统的复杂度;增加系统的理解和设计难度。

7.装饰者设计模式(Decorator Pattern)

装饰者设计模式是一种结构型设计模式,它可以在不改变一个对象的结构的情况下,给对象增加一些新的功能。

它的思想是:将一个类的功能进行加强,但是不改变它的结构。

装饰者设计模式的应用场景是:当你希望给一个类增加新的功能,而且不希望改变它的结构时,可以使用装饰者设计模式。

8.外观设计模式(Facade Pattern)

外观设计模式是一种结构型设计模式,它可以为复杂的子系统提供简单的接口,以便客户端可以方便地访问子系统。

它的思想是为复杂的子系统提供简单的接口,以便客户端可以方便地访问子系统。它的应用了依赖倒置原则。

应用场景是需要为复杂的子系统提供简单接口的场景。

9.桥接设计模式(Bridge Pattern)

桥接设计模式是一种结构型设计模式,它可以将抽象和实现解耦,从而让它们可以独立变化。它应用了接口隔离原则。

应用场景是需要将抽象和实现解耦的场景。

10.代理设计模式(Proxy Pattern)

代理设计模式是一种结构型设计模式,它可以为另一个对象提供一个替身或代理,以控制对这个对象的访问。它应用了迪米特法则。

应用场景是需要为另一个对象提供一个替身或代理的场景。

11.组合设计模式(Composite Pattern)

组合设计模式是一种结构型设计模式,它可以将对象组合成树形结构,从而使客户端可以使用统一的接口来处理单个对象和组合对象。它的原则是合成复用原则。

应用场景是需要将对象组合成树形结构的场景。

12.责任链设计模式(Chain of Responsibility Pattern)

它是一种行为设计模式,它使得请求发送者可以不需要知道处理者是谁,将请求发送给一系列的处理者,最终有处理者处理它。

它的原则是尽量减少请求发送者和处理者之间的耦合,有助于提高系统的灵活性和可扩展性。

13.命令设计模式(Command Pattern)

命令设计模式是一种行为设计模式,它将请求封装成一个对象,以便使用不同的请求、队列或者日志来参数化其他对象。

它的原则是将请求从它的发出者和执行者分离开来,以便实现低耦合、高内聚的系统结构。

14.解释器设计模式(Interpreter Pattern)

解释器设计模式是一种行为设计模式,它使用语法规则来解释使用者输入的数据,从而实现程序的功能。

它的原则是通过使用简单的语法规则来解释数据,以便更容易地实现程序功能。

15.迭代器设计模式(Iterator Pattern)

迭代器设计模式是一种行为设计模式,它使用迭代器对象来遍历容器,从而实现对容器中的元素的遍历。

它的原则是,将容器中的元素与其遍历操作分离开来,以便实现低耦合、高内聚的系统结构。

16.中介者设计模式(Mediator Pattern)

中介者设计模式是一种行为设计模式,它使用中介者对象来封装一组对象之间的交互,从而使这些对象之间的耦合度降低,提高系统的灵活性和可扩展性。它的原则是通过使用中介者对象来封装对象之间的交互,以便降低耦合度和提高系统的可扩展性。

17.观察者设计模式(Observer Pattern)

观察者设计模式是一种行为设计模式,它使用观察者对象来观察主题对象,以便当主题对象发生变化时,观察者对象可以获得通知。

它的原则是通过使用观察者对象来观察主题对象,以便当主题对象发生变化时,观察者对象可以获得通知。

18.状态设计模式(State Pattern)

态设计模式是一种行为设计模式,它使用状态对象来封装与状态有关的行为,以便使用不同的状态实现不同的行为。

它的原则是通过使用状态对象来封装与状态有关的行为,以便使用不同的状态实现不同的行为。

19.策略设计模式(Strategy Pattern)

策略设计模式是一种行为设计模式,它使用策略对象来封装可以互换的算法,以便使用不同的算法来解决不同的问题。

它的原则是通过使用策略对象来封装可以互换的算法,以便使用不同的算法来解决不同的问题。

20.模板方法设计模式(Template Pattern)

模板方法设计模式是一种行为设计模式,它使用模板方法来定义一个算法的基本结构,以便将一些具体的步骤延迟到子类中实现。它的原则是通过使用模板方法来定义算法的基本结构,以便将一些具体的步骤延迟到子类中实现。

21.备忘录设计模式(Memento Pattern)

备忘录设计模式是一种行为设计模式,它使用备忘录对象来存储对象的内部状态,以便在需要的时候对对象进行恢复。

它的原则是通过使用备忘录对象来存储对象的内部状态,以便在需要的时候对对象进行恢复。

22.访问者设计模式(Visitor Pattern)

访问者设计模式是一种行为设计模式,它使用访问者对象来访问某个对象,以便在不改变它的结构的情况下添加新的操作。

它的原则是通过使用访问者对象来访问某个对象,以便在不改变它的结构的情况下添加新的操作。

23.享元设计模式(Flyweight Pattern)

享元设计模式是一种用于性能优化的软件设计模式,通过共享对象来有效地支持大量细粒度的对象。

原理:享元设计模式通过共享技术实现相同或相似对象的重用。它通过为相似对象分配共享内存来节省内存,从而改善应用程序的性能。

优点:

1.可以极大提高应用程序的性能,提升应用程序的运行效率;

2.可以减少内存的使用量,提升应用程序的可扩展性;

3.可以提高应用程序的可维护性,减少对象的创建次数。

缺点:

1.实现享元设计模式需要分离出内部状态和外部状态,而识别内部状态需要充分的分析和编程实现;

2.在享元设计模式中,需要关联外部状态,这将增加复杂度;

3.使用享元设计模式会增加系统的维护复杂度,需要分离出内部状态和外部状态,而识别内部状态需要充分的分析和编程实现。

三、使用示例

//1.工厂方法设计模式

/**

在GOF出版的《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

**/

1.1简单工厂模式(Simple Factory)
1.1.1 JavaScript 1.6版本
代码语言:javascript代码运行次数:0运行复制
/**
 * 订单类
 */
function Order() {
  this.calculatePrice = function() {};
}
/**
 * 普通订单
 */
function NormalOrder() {
  this.calculatePrice = function(quantity, price) {
    return quantity * price;
  };
}
/**
 * 优惠订单
 */
function DiscountOrder() {
  this.calculatePrice = function(quantity, price) {
    if (quantity > 10) {
      return quantity * price * 0.9;
    } else {
      return quantity * price;
    }
  };
}
/**
 * 简单工厂类
 */
function OrderFactory() {
  this.createOrder = function(type) {
    switch (type) {
      case "normal":
        return new NormalOrder();
      case "discount":
        return new DiscountOrder();
      default:
        return new Order();
    }
  };
}
/**
 * 客户端代码
 */
var factory = new OrderFactory();
var normalOrder = factory.createOrder("normal");
var discountOrder = factory.createOrder("discount");
var price1 = normalOrder.calculatePrice(5, 10);
var price2 = discountOrder.calculatePrice(15, 10);
console.log(price1); // 50
console.log(price2); // 135

在这个示例中,我们定义了订单类 Order,并实现了计算价格的方法。在 NormalOrderDiscountOrder 类中,我们重写了父类中的方法,实现了不同类型的订单价格计算方式。在 OrderFactory 工厂类中,我们实现了 createOrder() 方法,根据传入的类型参数,返回了不同类型的订单。在客户端代码中,我们通过 OrderFactory 工厂类创建了不同类型的订单,并调用它们的方法进行价格计算。 这个示例中,我们通过简单工厂模式实现了订单的创建,使得客户端代码与具体实现解耦,更加灵活,适合使用者特别多。

1.1.2 ES6版本

在这个示例中,我们使用了 ES6 的 class 语法来定义订单类和订单类型类。在 NormalOrderDiscountOrder 类中,我们继承了 Order 类,并重写了父类中的 calculatePrice() 方法,实现了不同类型的订单价格计算方式。在 OrderFactory 工厂类中,我们使用了 class 语法,实现了 createOrder() 方法,根据传入的类型参数,返回了不同类型的订单。在客户端代码中,我们通过 OrderFactory 工厂类创建了不同类型的订单,并调用它们的方法进行价格计算。 这个示例中,我们仍然使用了简单工厂模式实现了订单的创建,使得客户端代码与具体实现解耦,更加灵活。同时,我们使用了 ES6 的语法,使得代码更加简洁易读,更加符合现代 JavaScript 的开发规范。

代码语言:javascript代码运行次数:0运行复制
/**
 * 订单类
 */
class Order {
  calculatePrice() {}
}
/**
 * 普通订单
 */
class NormalOrder extends Order {
  calculatePrice(quantity, price) {
    return quantity * price;
  }
}
/**
 * 优惠订单
 */
class DiscountOrder extends Order {
  calculatePrice(quantity, price) {
    if (quantity > 10) {
      return quantity * price * 0.9;
    } else {
      return quantity * price;
    }
  }
}
/**
 * 简单工厂类
 */
class OrderFactory {
  createOrder(type) {
    switch (type) {
      case "normal":
        return new NormalOrder();
      case "discount":
        return new DiscountOrder();
      default:
        return new Order();
    }
  }
}
/**
 * 客户端代码
 */
const factory = new OrderFactory();
const normalOrder = factory.createOrder("normal");
const discountOrder = factory.createOrder("discount");
const price1 = normalOrder.calculatePrice(5, 10);
const price2 = discountOrder.calculatePrice(15, 10);
console.log(price1); // 50
console.log(price2); // 135
1.2工厂方法模式(Factory Method)
//1.2.1 JavaScript 1.6版本
代码语言:javascript代码运行次数:0运行复制
// Coupon类
function Coupon(code) {
  this.code = code;
}
Coupon.prototype.getDiscount = function() {
  return 0;
}
// PercentageCoupon类
function PercentageCoupon(code, percentage) {
  Coupon.call(this, code);
  this.percentage = percentage;
}
PercentageCoupon.prototype = Object.create(Coupon.prototype);
PercentageCoupon.prototype.constructor = PercentageCoupon;
PercentageCoupon.prototype.getDiscount = function() {
  return this.percentage / 100;
}
// FixedAmountCoupon类
function FixedAmountCoupon(code, amount) {
  Coupon.call(this, code);
  this.amount = amount;
}
FixedAmountCoupon.prototype = Object.create(Coupon.prototype);
FixedAmountCoupon.prototype.constructor = FixedAmountCoupon;
FixedAmountCoupon.prototype.getDiscount = function() {
  return this.amount;
}
// CouponCreator接口
function CouponCreator() {}
CouponCreator.prototype.createCoupon = function() {
  throw new Error("This is an abstract method");
}
// PercentageCouponCreator类
function PercentageCouponCreator() {}
PercentageCouponCreator.prototype = Object.create(CouponCreator.prototype);
PercentageCouponCreator.prototype.constructor = PercentageCouponCreator;
PercentageCouponCreator.prototype.createCoupon = function(code, percentage) {
  return new PercentageCoupon(code, percentage);
}
// FixedAmountCouponCreator类
function FixedAmountCouponCreator() {}
FixedAmountCouponCreator.prototype = Object.create(CouponCreator.prototype);
FixedAmountCouponCreator.prototype.constructor = FixedAmountCouponCreator;
FixedAmountCouponCreator.prototype.createCoupon = function(code, amount) {
  return new FixedAmountCoupon(code, amount);
}
// 使用示例
var percentageCouponCreator = new PercentageCouponCreator();
var fixedAmountCouponCreator = new FixedAmountCouponCreator();
var coupon1 = percentageCouponCreator.createCoupon("SUMMER2021", 20);
var coupon2 = fixedAmountCouponCreator.createCoupon("SALE2021", 50);
console.log(coupon1.getDiscount()); // 0.2
console.log(coupon2.getDiscount()); // 50
//1.2.2 ES6版本

/**

在这个示例中,我们使用了 ES6 的 class 语法来定义订单类和订单类型类。在 NormalOrderDiscountOrder 类中,我们继承了 Order 类,并重写了父类中的 calculatePrice() 方法,实现了不同类型的订单价格计算方式。在 OrderFactory 工厂方法接口中,我们定义了一个抽象方法 createOrder(),用于创建订单。在 NormalOrderFactoryDiscountOrderFactory 工厂类中,我们实现了 createOrder() 方法,分别创建了不同类型的订单。在客户端代码中,我们通过 NormalOrderFactoryDiscountOrderFactory 工厂类分别创建了不同类型的订单,并调用它们的方法进行价格计算。 这个示例中,我们使用了工厂方法模式实现了订单的创建,使得客户端代码与具体实现解耦,更加灵活。同时,我们使用了 ES6 的语法,使得代码更加简洁易读,更加符合现代 JavaScript 的开发规范。

**/

代码语言:javascript代码运行次数:0运行复制
/**
 * 订单类
 */
class Order {
  calculatePrice() {}
}
/**
 * 普通订单
 */
class NormalOrder extends Order {
  calculatePrice(quantity, price) {
    return quantity * price;
  }
}
/**
 * 优惠订单
 */
class DiscountOrder extends Order {
  calculatePrice(quantity, price) {
    if (quantity > 10) {
      return quantity * price * 0.9;
    } else {
      return quantity * price;
    }
  }
}
/**
 * 工厂方法接口
 */
class OrderFactory {
  createOrder() {}
}
/**
 * 普通订单工厂
 */
class NormalOrderFactory extends OrderFactory {
  createOrder() {
    return new NormalOrder();
  }
}
/**
 * 优惠订单工厂
 */
class DiscountOrderFactory extends OrderFactory {
  createOrder() {
    return new DiscountOrder();
  }
}
/**
 * 客户端代码
 */
const normalFactory = new NormalOrderFactory();
const discountFactory = new DiscountOrderFactory();
const normalOrder = normalFactory.createOrder();
const discountOrder = discountFactory.createOrder();
const price1 = normalOrder.calculatePrice(5, 10);
const price2 = discountOrder.calculatePrice(15, 10);
console.log(price1); // 50
console.log(price2); // 135

//2.抽象工厂设计模式

//2.1 JavaScript 1.6版本

/*

在这个示例中,我们定义了抽象工厂类 AbstractCouponFactory,其中包含了创建优惠券和活动的抽象方法 createCoupon() 和 createPromotion()。然后,我们定义了具体的优惠券类 Coupon 和活动类 Promotion,并实现了它们的具体行为。在 MotherAndBabyCouponFactory 工厂类中,我们实现了 createCoupon() 和 createPromotion() 方法,分别返回了 NewUserCoupon 类型的优惠券和 DoubleElevenPromotion 类型的活动。在客户端代码中,我们通过 MotherAndBabyCouponFactory 工厂类创建了优惠券和活动,并调用它们的方法进行使用和启动。

这个示例中,我们通过抽象工厂模式实现了优惠券和活动的创建,使得客户端代码与具体实现解耦,更加灵活。

*/

代码语言:javascript代码运行次数:0运行复制
/**
 * 抽象工厂类
 */
function AbstractCouponFactory() {
    this.createCoupon = function() {};
    this.createPromotion = function() {};
}
/**
 * 优惠券类
 */
function Coupon() {
    this.useCoupon = function() {};
}
/**
 * 新用户优惠券
 */
function NewUserCoupon() {
    this.useCoupon = function() {
        console.log("使用新用户优惠券");
    };
}
/**
 * 活动类
 */
function Promotion() {
    this.startPromotion = function() {};
}
/**
 * 双十一活动
 */
function DoubleElevenPromotion() {
    this.startPromotion = function() {
        console.log("开始双十一活动");
    };
}
/**
 * 母婴类优惠券工厂
 */
function MotherAndBabyCouponFactory() {
    this.createCoupon = function() {
        return new NewUserCoupon();
    };
    this.createPromotion = function() {
        return new DoubleElevenPromotion();
    };
}
/**
 * 客户端代码
 */
var factory = new MotherAndBabyCouponFactory();
var coupon = factory.createCoupon();
var promotion = factory.createPromotion();
coupon.useCoupon();
promotion.startPromotion();
//2.2 ES6 版本示例代码

/*

在这个示例中,我们定义了抽象工厂类 AbstractCouponFactory,其中包含了创建优惠券和活动的抽象方法 createCoupon() 和 createPromotion()。然后,我们定义了具体的优惠券类 Coupon 和活动类 Promotion,并实现了它们的具体行为。在 MotherAndBabyCouponFactory 工厂类中,我们继承了 AbstractCouponFactory 类,并实现了 createCoupon() 和 createPromotion() 方法,分别返回了 NewUserCoupon 类型的优惠券和 DoubleElevenPromotion 类型的活动。在客户端代码中,我们通过 MotherAndBabyCouponFactory 工厂类创建了优惠券和活动,并调用它们的方法进行使用和启动。

这个示例中,我们通过抽象工厂模式实现了优惠券和活动的创建,使得客户端代码与具体实现解耦,更加灵活。需要注意的是,这个示例使用了 ES6 的语法,需要在支持 ES6 的环境中运行。

*/

代码语言:javascript代码运行次数:0运行复制
/**
 * 抽象工厂类
 */
class AbstractCouponFactory {
  constructor() {
    this.createCoupon = function() {};
    this.createPromotion = function() {};
  }
}
/**
 * 优惠券类
 */
class Coupon {
  constructor() {
    this.useCoupon = function() {};
  }
}
/**
 * 新用户优惠券
 */
class NewUserCoupon extends Coupon {
  constructor() {
    super();
    this.useCoupon = function() {
      console.log("使用新用户优惠券");
    };
  }
}
/**
 * 活动类
 */
class Promotion {
  constructor() {
    this.startPromotion = function() {};
  }
}
/**
 * 双十一活动
 */
class DoubleElevenPromotion extends Promotion {
  constructor() {
    super();
    this.startPromotion = function() {
      console.log("开始双十一活动");
    };
  }
}
/**
 * 母婴类优惠券工厂
 */
class MotherAndBabyCouponFactory extends AbstractCouponFactory {
  constructor() {
    super();
    this.createCoupon = function() {
      return new NewUserCoupon();
    };
    this.createPromotion = function() {
      return new DoubleElevenPromotion();
    };
  }
}
/**
 * 客户端代码
 */
const factory = new MotherAndBabyCouponFactory();
const coupon = factory.createCoupon();
const promotion = factory.createPromotion();
coupon.useCoupon();
promotion.startPromotion();

//3.单例设计模式

/*

单例设计模式的思想是将类的实例化控制在一个对象中,一个类只能有一个实例。

它的应用场景主要是在需要全局控制的情况下,例如在电商平台中,订单流程的控制,可以使用单例设计模式。

在多线程环境下,双重检查锁和 volatile 关键字的组合可以保证单例模式的线程安全性和正确性。

*/

//3.2 ES6版本

/**

在这个示例中,我们使用了 ES6 的 class 语法来定义订单类,并在构造函数中实现了单例模式。在构造函数中,我们首先判断 Order.instance 是否已经存在,如果存在则返回该实例,否则创建一个新的实例并将其赋值给 Order.instance。在客户端代码中,我们分别创建了两个订单对象 order1order2,并通过比较它们的引用是否相同来判断它们是否是同一个实例。 这个示例中,我们使用了单例模式来保证了只有一个订单实例存在,从而避免了重复创建订单实例的问题。同时,我们使用了 ES6 的语法,使得代码更加简洁易读,更加符合现代 JavaScript 的开发规范。

**/

代码语言:javascript代码运行次数:0运行复制
/**
 * 订单类
 */
class Order {
  constructor() {
    if (typeof Order.instance === 'object') {
      return Order.instance;
    }
    Order.instance = this;
  }
}
/**
 * 客户端代码
 */
const order1 = new Order();
const order2 = new Order();
console.log(order1 === order2); // true

//4.原型设计模式

/*

原型设计模式的思想是通过复制原型来创建一个新的对象。它的应用场景一般是在创建复杂对象时,可以先复制一个原型来进行一些初始化的工作,

然后在对其进行修改。在电商平台中,可以使用原型设计模式来创建订单对象,避免重复的初始化工作。

//4.2 ES6版本

/**

在这个示例中,我们定义了一个Order类作为订单类,并在类的原型上定义了一个clone方法,用于复制当前订单对象。在clone方法中,我们使用Object.assign()方法复制了当前订单对象,并返回新的订单对象。然后我们创建了一个订单对象order1,并克隆了一个新的订单对象order2,最后修改了order2的属性,但原订单对象order1并没有受到影响。

**/

代码语言:javascript代码运行次数:0运行复制
// 定义订单类
class Order {
  constructor(id, customer, total) {
    this.id = id;
    this.customer = customer;
    this.total = total;
  }
  clone() {
    // 使用Object.assign()方法复制当前对象
    return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
  }
}
// 创建订单对象
const order1 = new Order(1, 'John Doe', 100);
console.log(order1); // 输出:Order { id: 1, customer: 'John Doe', total: 100 }
// 克隆订单对象
const order2 = order1.clone();
console.log(order2); // 输出:Order { id: 1, customer: 'John Doe', total: 100 }
// 修改克隆对象的属性
order2.id = 2;
order2.customer = 'Jane Doe';
order2.total = 200;
console.log(order2); // 输出:Order { id: 2, customer: 'Jane Doe', total: 200 }
// 原对象不受影响
console.log(order1); // 输出:Order { id: 1, customer: 'John Doe', total: 100 }

//5.建造者设计模式

/*

建造者设计模式的思想是将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。它的应用场景一般是在创建复杂对象时,

可以将复杂对象的创建过程进行拆分,使得创建过程更加清晰。在电商平台中,可以使用建造者设计模式来创建订单对象,将复杂的构建过程分解成

几个步骤,从而使得创建过程更加清晰。

*/

//5.2 ES6版本

/*

在这个示例中,我们定义了一个Order类作为订单类,并定义了一个OrderBuilder类作为订单建造者类。在OrderBuilder类中,我们定义了一些方法,用于设置订单的属性和计算订单的总价,并在build方法中返回一个新的Order对象。然后我们创建了一个订单建造者对象orderBuilder,并使用该建造者对象创建了一个订单对象order。最后我们打印了订单对象。

*/

代码语言:javascript代码运行次数:0运行复制
// 定义订单类
class Order {
  constructor(id, customer, items, total) {
    this.id = id;
    this.customer = customer;
    this.items = items;
    this.total = total;
  }
}
// 定义订单建造者类
class OrderBuilder {
  constructor() {
    this.id = null;
    this.customer = null;
    this.items = [];
    this.total = 0;
  }
  setId(id) {
    this.id = id;
    return this;
  }
  setCustomer(customer) {
    this.customer = customer;
    return this;
  }
  addItem(item) {
    this.items.push(item);
    return this;
  }
  setTotal() {
    let total = 0;
    this.items.forEach(item => {
      total += item.price * item.quantity;
    });
    this.total = total;
    return this;
  }
  build() {
    return new Order(this.id, this.customer, this.items, this.total);
  }
}
// 创建订单建造者对象
const orderBuilder = new OrderBuilder();
// 使用订单建造者创建订单对象
const order = orderBuilder.setId(1)
                         .setCustomer('John Doe')
                         .addItem({ product: 'product1', price: 10, quantity: 2 })
                         .addItem({ product: 'product2', price: 20, quantity: 3 })
                         .setTotal()
                         .build();
console.log(order); // 输出:Order { id: 1, customer: 'John Doe', items: [ { product: 'product1', price: 10, quantity: 2 }, { product: 'product2', price: 20, quantity: 3 } ], total: 70 }

//6.适配器设计模式

/*

适配器设计模式的思想是将一个类的接口转换成客户希望的另外一个接口。它的应用场景一般是在原有的类接口不符合客户需求的时候,

可以使用适配器设计模式来实现接口的转换。在电商平台中,可以使用适配器设计模式来转换订单对象的接口,使得订单对象更加符合客户的需求。

*/

//6.1 Javascript 1.6版本

/*

在这个示例代码中,我们定义了目标接口 Discount,CouponAdapter 类继承自目标接口 Discount,并实现了这个接口的方法。将 Coupon 类的接口转换成目标接口 Discount。客户端代码使用 Coupon 类和 CouponAdapter 类来获取优惠金额和优惠券类型。

*/

代码语言:javascript代码运行次数:0运行复制
// 目标接口-Target 
function Discount() {}
Discount.prototype.getDiscount = function() {};
Discount.prototype.getType = function() {};
// 优惠券类-Adaptee
function Coupon(name,value) {
this.name=name;
this.value=value;
}
Coupon.prototype.getValue = function() {
  return this.value;
};
Coupon.prototype.getName = function() {
  return this.name;
};
// 优惠券适配器类-Adapter
function CouponAdapter(coupon) {
  this.coupon = coupon;
}
CouponAdapter.prototype = Object.create(Discount.prototype);
CouponAdapter.prototype.constructor = CouponAdapter;
CouponAdapter.prototype.getDiscount = function() {
  return this.coupon.getValue();
};
CouponAdapter.prototype.getType = function() {
  return this.coupon.getName();
};
// 客户端代码
var discount = new Discount(); // 创建目标接口
var coupon = new Coupon('7折券',0.7); // 创建优惠券
console.log(coupon.getValue()); // 输出:0.7
console.log(coupon.getName()); // 输出:7折券
var couponAdapter = new CouponAdapter(coupon); // 创建优惠券适配器
console.log(couponAdapter.getDiscount()); // 输出:0.7
console.log(couponAdapter.getType()); // 输出:7折券
//6.2 ES6版本

/**

在这个示例中,我们使用了适配器设计模式来将第三方商家提供的优惠券类(Adaptee)适配成本地商家提供的优惠券类(Target)。适配器类(Adapter)继承了本地商家提供的优惠券类(Target),并且通过组合的方式持有了第三方商家提供的优惠券类(Adaptee)。适配器类(Adapter)实现了本地商家提供的优惠券类(Target)的接口,但是在实现的时候会调用第三方商家提供的优惠券类(Adaptee)的接口。这样,我们就可以在本地商家的优惠券管理器中使用第三方商家的优惠券了。

*/

代码语言:javascript代码运行次数:0运行复制
// 第三方商家提供的优惠券类(Adaptee)
class ThirdPartyCoupon {
  constructor(code, discount) {
    this.code = code;
    this.discount = discount;
  }
  getCode() {
    return this.code;
  }
  getDiscount() {
    return this.discount;
  }
}
// 本地商家提供的优惠券类(Target)
class LocalCoupon {
  constructor(name, value) {
    this.name = name;
    this.value = value;
  }
  getName() {
    return this.name;
  }
  getValue() {
    return this.value;
  }
}
// 适配器类(Adapter)
class CouponAdapter extends LocalCoupon {
  constructor(adaptee) {
    super(adaptee.getCode(), adaptee.getDiscount());
  }
  getName() {
    return `Third Party Coupon ${this.code}`;
  }
  getValue() {
    return this.discount;
  }
}
// 本地商家优惠券管理器(Client)
class LocalCouponManager {
  constructor() {
    this.coupons = [];
  }
  addCoupon(coupon) {
    this.coupons.push(coupon);
  }
  getCoupons() {
    return this.coupons;
  }
}
// 使用示例
const thirdPartyCoupon = new ThirdPartyCoupon('ABC123', 20);
const couponAdapter = new CouponAdapter(thirdPartyCoupon);
const localCouponManager = new LocalCouponManager();
localCouponManager.addCoupon(couponAdapter);
// 打印本地商家优惠券列表
localCouponManager.getCoupons().forEach(coupon => {
  console.log(coupon.getName(), coupon.getValue());
});

//装饰者设计模式

/*

装饰者设计模式的思想是动态地将责任附加到对象上。它的应用场景一般是在原有类不满足客户需求时,可以在不改变原有类的基础上通过

装饰者设计模式来动态地增加新的功能。在电商平台中,可以使用装饰者设计模式来为订单对象增加新的功能,比如折扣功能,而不改变原有的订单对象。

*/

//外观设计模式

/*

外观设计模式的思想是为子系统中的一组接口提供一个一致的界面,从而使子系统更加容易使用。它的应用场景一般是在复杂的系统中,可以使用外观设计模式

来简化系统的接口,从而使系统更加容易使用。在电商平台中,可以使用外观设计模式来简化订单系统的接口,使得订单系统更加容易使用。

*/

//桥接设计模式

/*

桥接设计模式的思想是将抽象和实现分离,使它们可以独立变化。它的应用场景一般是在多个变化维度存在时,可以使用桥接设计模式来将抽象和实现分离,

从而使抽象和实现可以独立变化。在电商平台中,可以使用桥接设计模式来创建购物车对象,将购物车的抽象和实现分离,从而使得购物车的抽象和实

现可以独立变化。

*/

//代理设计模式

/*

代理设计模式的思想是为其他对象提供一种代理以控制对这个对象的访问。它的应用场景一般是在访问某个对象时,可以使用代理设计模式来控制对这个对象的访问。

在电商平台中,可以使用代理设计模式来访问购物车对象,从而控制对购物车的访问。

*/

//组合设计模式

/*

组合设计模式的思想是将对象组合成树形结构,以表示部分-整体的层次结构。它的应用场景一般是在树形结构中,可以使用组合设计模式来将对象组合成树形结构,

从而表示部分-整体的层次结构。在电商平台中,可以使用组合设计模式来组织购物车对象,将购物车的对象组合成树形结构,从而表示部分-整体的层次结构。

*/

//责任链设计模式

/*

责任链设计模式的思想是将请求的处理者分开,每个处理者对请求做出响应,从而形成一条链,每个处理者都可以决定是否将请求传递给下一个处理者。

它的应用场景一般是在多种处理方法存在时,可以使用责任链设计模式来将请求的处理者分开,从而使得处理者之间形成一条链。在电商平台中,

可以使用责任链设计模式来处理购物车对象,将购物车的处理者分开,从而使得处理者之间形成一条链。

*/

//命令设计模式

/*

命令设计模式的思想是将请求封装成一个对象,以便使用不同的请求、队列或者日志来参数化其他对象。它的应用场景一般是在请求不同时,

可以使用命令设计模式来将请求封装成对象,从而使用不同的请求参数化其他对象。在电商平台中,可以使用命令设计模式来执行购物车对象的操作,

将购物车的操作封装成对象,从而使用不同的请求参数化其他对象。

*/

//解释器设计模式

/*解释器设计模式的思想是为一个特定的上下文定义一个语言,并定义该语言的文法,然后使用该文法来解释语言中的句子。它的应用场景一般是在特定上下文中,可以使用解释器设计模式来定义一种语言,并使用该语言的文法来解释句子。在电商平台中,可以使用解释器设计模式来解释购物车对象的操作,定义一种语言,来描述购物车的操作,然后使用该语言的文法来解释句子,从而完成购物车的操作。

*/

//迭代器设计模式

/*

迭代器设计模式的思想是提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。它的应用场景一般是在聚合对象中,

可以使用迭代器设计模式来提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。在电商平台中,可以使用迭代器

设计模式来遍历支付对象,提供一种方法顺序访问一个支付对象中的各个元素,而又不暴露该对象的内部表示。

*/

//中介者设计模式

/*

中介者设计模式的思想是用一个中介对象来封装一系列对象之间的交互,使各对象之间不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

它的应用场景一般是在多个对象之间存在复杂的引用关系时,可以使用中介者设计模式来封装这些复杂的引用关系,使各对象之间不需要显式地相互引用,

从而使其耦合松散。在电商平台中,可以使用中介者设计模式来封装支付对象之间的交互,使支付对象之间不需要显式地相互引用,从而使其耦合松散。

*/

//观察者设计模式

/*

观察者设计模式的思想是定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。它的应用场景一般是在

对象间存在一对多的依赖关系时,可以使用观察者设计模式来定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知

并自动更新。在电商平台中,可以使用观察者设计模式来定义支付对象之间的一对多的依赖关系,使得每当一个支付对象改变状态,则所有依赖于它的支付对象都会得

到通知并自动更新。

*/

//状态设计模式

/*

状态设计模式的思想是允许一个对象在其内部状态改变时改变它的行为,这个对象看起来就像是改变了它的类。它的应用场景一般是在一个对象的行为取决于它的状态,

可以使用状态设计模式来允许一个对象在其内部状态改变时改变它的行为,这个对象看起来就像是改变了它的类。在电商平台中,可以使用状态设计模式来允许支付对象在

其内部状态改变时改变它的行为,这个支付对象看起来就像是改变了它的类。

*/

//策略设计模式

/*

策略设计模式的思想是定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。它的应用场景一般是在多个类只有在算法或行为上稍有不同的情况下,

可以使用策略设计模式来定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。在电商平台中,可以使用策略设计模式来定义支付算法,把它们一个个

封装起来,并且使它们可以相互替换。

*/

//模板方法设计模式

/*模板方法设计模式的思想是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中实现。它的应用场景一般是在一次性实现一个算法的不变部分,并将可变部分留给

子类去实现时,可以使用模板方法设计模式来定义一个操作中的算法的骨架,而将一些步骤延迟到子类中实现。在电商平台中,可以使用模板方法设计模式来定义支付操作的算

法的骨架,而将一些步骤延迟到子类中实现。

*/

备忘录设计模式

/*

备忘录设计模式的思想原则是:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到

原先保存的状态。应用场景:备忘录设计模式可以用于撤销操作等场景,比如电商平台的优惠券业务,可以使用备忘录设计模式来记录优惠券使用的状态,以便在需要撤销

操作时可以将优惠券状态恢复。 以电商平台的优惠券业务为例,具体的java代码可以参考如下:

*/

//访问者设计模式

/*

封装一些作用于某种数据结构的元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。

应用场景:访问者设计模式适用于数据结构相对稳定的系统,把数据结构和算法解耦,可以较好的应对变化。比如电商平台的优惠券业务,

可以通过访问者设计模式对优惠券进行统一管理,根据不同的优惠券类型采用不同的操作。以电商平台的优惠券业务为例,具体的java代码可以参考如下:

*/

//解释器设计模式

/*

为特定的语言创建一个解释器,用来解释该语言中的句子。

应用场景:解释器设计模式适用于语言文法比较简单的情况,比如电商平台的优惠券业务,可以通过解释器设计模式

来解析优惠券的使用规则,比如满多少金额可用等。以电商平台的优惠券业务为例,具体的java代码可以参考如下:

*/

//调停者设计模式

/*

用一个中介对象来封装一系列的对象交互,使各对象不需要显式地相互引用,从而使耦合松散,而且可以独立的改变它们之间的交互。

应用场景:调停者设计模式适用于多个对象之间紧密耦合的情况,比如电商平台的优惠券业务,可以通过调停者设计模式来调节优惠券发放、使用、核销等各个环节之间的关系

,以便达到高效的运营管理。以电商平台的优惠券业务为例,具体的java代码可以参考如下:

*/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2023-03-13,如有侵权请联系 cloudcommunity@tencent 删除对象接口设计模式javascript电商

本文标签: JavaScript版本的23种常用设计模式快速入门教程