likes
comments
collection
share

js设计模式(二)-创建型模式

作者站长头像
站长
· 阅读数 34

创建型设计模式介绍

在软件工程中,创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。

创建型模式由两个主导思想构成。一是将系统使用的具体类封装起来,二是隐藏这些具体类的实例创建和结合的方式。

创建型模式又分为对象创建型模式和类创建型模式。对象创建型模式处理对象的创建,类创建型模式处理类的创建。详细地说,对象创建型模式把对象创建的一部分推迟到另一个对象中,而类创建型模式将它对象的创建推迟到子类中。

原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

如果使用原型模式,我们只需要调用负责克隆的方法,便能完成同样的功能。 原型模式的实现关键,是语言本身是否提供了clone方法。ECMAScript 5提供了Object.create方法,可以用来克隆对象。

const Car = function () {
  this.color = "red";
  this.brand = "大众";
  this.mileage = 10000;
};

const car = new Car();

console.log("car:before", car);
// car:before Car { color: 'red', brand: '大众', mileage: 10000 }

car.color = "blue";
car.brand = "BMW";
car.mileage = 999;
car.sayHello = () => console.log("sayHello Func => ", "hello,world!");

console.log("car:after", car);
// car:after Car { color: 'blue', brand: 'BWM', mileage: 999 }
const bentch = Object.create(car);

console.log("bentch:", bentch);
console.log("bentch.color:", bentch.color);
console.log("bentch.brand:", bentch.brand);
console.log("bentch.mileage:", bentch.mileage);
// bentch: Car {}
// bentch.color: blue
// bentch.brand: BWM
// bentch.mileage: 999

bentch.sayHello();
// sayHello Func =>  hello,world!

js设计模式(二)-创建型模式

说实在的,原型模式看了好多人在介绍,并没有一个很清晰的认知。只是认识到了这两点:

  1. 可以这么理解,所谓原型是依赖于使用场景的,它 使用到了 Object.create 方法去克隆了已经存在的对象,并对原来的数据进行改动的时候不会对原来的数据造成影响。
  2. 感觉这种方法非常简单,适用于比较简单的场景,能迅速的“实例化”一个新的对象出来。

单例模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。
class MessageClass {
  constructor(config) {
    if (!MessageClass.instance) {
      const baseConfig = {
        color: "red",
        timeOut: 3000,
      };

      this.config = Object.assign(baseConfig, config);
      MessageClass.instance = this;
    }
    return MessageClass.instance;
  }

  success(msg) {
    this.config.color = "green";
    this.msg = msg;
    this.print("success", msg);
  }

  error(msg) {
    this.config.color = "red";
    this.msg = msg;
    this.print("error", msg);
  }

  print(type) {
    console.log(
      type,
      "::",
      "color=",
      this.config.color,
      "msg=",
      this.msg,
      "timeOut=",
      this.config.timeOut
    );
  }
}

const Message = new MessageClass({ timeOut: 5000 });
const Message2 = new MessageClass({ timeOut: 8000 });

Message.success("成功消息!");
Message.error("错误消息!");
Message2.success("成功消息!");
Message2.error("错误消息!");
console.log("Message === Message2 : ", Message === Message2);

js设计模式(二)-创建型模式

如上所示,我实现了一个 Message 组件,类似 ElementUI 里面的 message 组件的简化版本。

这个无疑是最能诠释单例模式的一个常见的场景了,如打印结果所示,第二次实例化 MessageClass 的时候,入参config并没有生效,这是因为,第一次已经将 intence 创建出来了,以后再也不会走 constroctor 里面的逻辑了,想要修改config,就需要再暴露一个方法去 setConfig 了。

为什么要 Message 要用单例模式呢?因为要保证 每个 Message 不会互相影响,这就要在同一个地址把所有的打印信息放在一起,然后统一去实现动画效果。

其他的使用场景主要是 single-spa 的场景下,例如 vue-router,vuex,dialog,confirm ...

工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

class User {
  constructor(role, pages) {
    this.role = role;
    this.pages = pages;
  }

  static UserFactory(role) {
    switch (role) {
      case "superadmin":
        return new User(role, ["home", "user-manage", "news-manage"]);
        break;
      case "admin":
        return new User(role, ["home", "news-manage"]);
        break;
      case "user":
        return new User(role, ["home"]);
        break;
      default:
        throw "参数错误!";
        break;
    }
  }
}

const sadmin = User.UserFactory("superadmin");
const admin = User.UserFactory("admin");
const user = User.UserFactory("user");
console.log(sadmin);
console.log(admin);
console.log(user);

const err = User.UserFactory("error");

js设计模式(二)-创建型模式

如上所示,是从 B 站视频上的一个例子,用来鉴权所使用的。其实这个逻辑用在这里有点牵强。

但是用来理解套路是够了,就是根据实例化的时候的参数不同,返回不同的对象实例。

抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

这个就不粘代码了,工厂模式中可以看到,最终返回的是一个实例后的对象,而抽象工厂模式是使用一个公共的factory方法返回class原型。使用方法也多了一步:

const UserClass = userClassFactory('superadmin')
let user = new UserClass('张三')

建造者模式(生成器模式)

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

我看了一下相关的介绍,这个模式的使用场景不是很常见,但是有个例子还是很容易理解的:

// 类的链式调用

class CarBuilder {
  constructor(name) {
    this.name = name;
  }

  buildPart1(params) {
    this.part1 = params;
    return this;
  }

  buildPart2(params) {
    this.part2 = params;
  }
}

const bentch = new CarBuilder("bentch");
bentch.buildPart1({ color: "red" }).buildPart2({ color: "blue" });

console.log(bentch);

js设计模式(二)-创建型模式

如上所示,如果有一个按顺序实现的比较复杂的需求,例如一个多层循环的tab结构,就需要先实现头部,然后绑定头部事件,按照头部信息触发点击事件切换内容。

同样,链式调用是最直观的方法,其实正常的逻辑会有一个组装方法,把各个模块分开后由 组装方法 build 在一起。

后记

其实,本文的几段代码都是为了演示设计模式而专门杜撰的,说句不好听的,就是为了用而用。

而实际开发中,一般都是多个模式混合着使用,学习这些模式必须学习到其核心原理,而不是要背会这些代码。

简单总结一下:

  1. 原型模式:基于语言的原生语法,进行新的对象的创建和构建,适用于比较灵活的场景;
  2. 单例模式:整个页面中涉及到的所有实例,都来自于同一个,适用于来自于同一个模型的多个不同实例,但是需要统一管理所有的实例的场景下;
  3. 工厂模式:由一个入口,返回多个同类型的实例对象,适用于同属大类但是又有些许区别的的场景;
  4. 抽象工厂模式:在工厂模式的基础上,同一个入口返回差别比较大的实例对象原型,适用于比较复杂的一对多的创建场景;
  5. 建造者模式:将整个大业务进行拆解,进行依次组装,适用于流程比较复杂且有前后依赖关系的场景。

参考文档

转载自:https://juejin.cn/post/7175817588323123256
评论
请登录