前端常用的设计模式

40 阅读5分钟

1.单例设计模式

单例设计模式:

使用场景:

  • 重复引入第三方库
  • VueX全局状态管理

一个构造函数一生只能有一个实例,不管new多少次都是只有一个实例,单例模式核心代码:

function Person() {
  this.name = "Jack";
}

let instance = null;

function SingleTon() {
  if (!instance) {
    instance = new Person();
  }
  return instance;
}
const p1 = SingleTon();
const p2 = SingleTon();
console.log(p1 === p2); //输出true

第一次调用singleton的时候,instance是null,执行new person给instance赋值。从此之后instance就是一个person实例

第二次调用singleTon的时候,此时instance是第一次new出来的实例,if条件不会执行了,返回的是第一次实例的地址

对单例设计模式的改造:

单例设计模式改造:需要把instance变量保存下来,singleton是一个函数,里面可以判断 可以返回,并且以闭包的形式返回。

const SingleTon = (function () {
  // 这个变量因为在一个不会被销毁的函数执行空间里面,所以会一直存在
  let instance = null;
  function Person() {
    this.name = "Jack";
  }
  return function singleTon() {
    if (!instance) {
      instance = new Person();
    }
    return instance;
  };
})();
const p1 = SingleTon();
const p2 = SingleTon();
console.log(p1 === p2); //输出true

2观察者模式

概念:观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。

举个例子:我们坐在教室里,老师是观察者,我们是被观察者,当被观察者触发一些条件时,观察者就会触发技能。

代码实例:

创建观察者类

class Observer {
  // name身份
  // fn技能
  constructor(name, fn = () => {}) {
    this.name = name;
    this.fn = fn;
  }
}

创建两个观察者

```js
const bzr = new Observer("班主任", () => {
  console.log("叫家长");
});

const xz = new Observer("校长", () => {
  console.log("把班主任找来");
});

创建被观察者

/**
 *1.创建被观察者
 *  属性,有自己的状态
 *  队列:记录都有谁观察者自己 ,数组[]
 *  方法,能够设置自己的状态。要触发这个方法改变状态
 *  方法,添加观察者
 */
 
 class Subject {
  constructor(state) {
    // 记录自己的状态
    this.state = state;
    // 数组,记录观察自己的人
    this.Observers = [];
  }
  //   设置自己的状态
  setState(state) {
    this.state = state;

    // 触发观察者的技能
    this.Observers.forEach((item) => {
      // 告诉观察者我改变了什么状态
      //   item就是一个一个对象
      //   把每一个观察者的技能触发掉
      item.fn();
    });
  }

  //   添加观察者
  addObserver(obs) {
    // some()
    //   数组去重
    this.Observers = this.Observers.filter((item) => item !== obs);
    this.Observers.push(obs);
  }

  //  删除观察者
  delObserver(obj) {
    this.Observers = this.Observers.filter((item) => item !== obj);
  }
}
const xiaoming = new Subject("学习");
xiaoming.addObserver(bzr);
xiaoming.addObserver(xz);
xiaoming.setState("11111");

查看结果:

叫家长

把班主任找来

3.发布订阅模式

基本概念:发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

有一个对象,有人一直看着他,当这个对象发生变化的时候,第三方通知这个看着的人,触发技能

代码:

class Observer {
  constructor() {
    this.message = {};
  }

  // 向消息队列里面添加内容
  on(type, fn) {
    // type是行为
    // 行为发生的时候,要做的事情
    // 计入消息队列
    if (!this.message[type]) {
      // 如果没有该事件,就创建一个该类型的新的消息队列
      this.message[type] = [];
    }
    this.message[type].push(fn);
  }

  // 删除消息队列的内容
  off(type, fn) {
    // fn 不存在
    if (!fn) {
      // 直接把这个事件取消掉
      delete this.message[type];
      return;
    }

    // 没有订阅过该消息
    if (!this.message[type]) {
      return;
    }

    // 确实订阅过
    this.message[type] = this.message[type].filter((item) => item !== fn);
  }

  // 触发消息队列
  trigger(type) {
    // 判断是否订阅过
    if (!this.message[type]) {
      return;
    }
    this.message[type].forEach((item) => {
      //  item就是每一个函数
      item();
    });
  }
}

const person1 = new Observer();
person1.on("a", handlerA);
person1.on("a", handlerB);

person1.trigger("a");
function handlerA() {
  console.log("A");
}
function handlerB() {
  console.log("B");
}

4. 策略模式

策略,指的是可以实现目标的方案集合,在某些特定情况下,策略之间是可以相互替换的。

比如在外卖平台上的这些优惠。满减、会员和红包等,每一个大项优惠都具体包含了多个优惠方案。如满减活动中,可以同时有满28减18、满58减38等。会员包含普通会员、超级会员等。

每一个优惠方式下面的多个优惠方案,其实都是一个策略。这些策略之间是相互排斥、可替换的。并且是有一定的优先级顺序的。

  • 一个问题解决多个解决方案: 不一定要用哪一个,而且还会继续增加多个方案
const calcPrice = (function () {
  const sale = {
  // 100 -10 
    "100_10": function (price) {
      return (price -= 10);
    },
    
  //200 - 25 
    "200_25": function (price) {
      return (price -= 25);
    },
    "80%": function (price) {
      return (price *= 0.8);
    },
  };
  //   计算价格
  function calcPrice(price, type) {
    // 判断对象里面有没有该折扣类型
    if (!sale[type]) {
      return "没有该折扣类型";
    }

    // 如果有就执行
    const result = sale[type](price);
    return result;
  }
  //   添加折扣
  calcPrice.add = function (type, fn) {
    //  专门用来添加折扣
    //  判断该折扣是否存在
    if (sale[type]) return "折扣已经存在";

    // 添加该折扣
    sale[type] = fn;
  };

  calcPrice.del = function (type) {
    delete sale[type];
  };

  return calcPrice;
})();


calcPrice.add("70%", function (price) {
  return (price *= 0.7);
});
const res = calcPrice(320, "100_10");
const res1 = calcPrice(320, "70%");

console.log("--------------------------------------");
calcPrice.del("70%");

const rest = calcPrice(320, "70%");
console.log(rest);