JavaScript常见设计模式

单例模式

概念:这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。

作用:保证全局只有一个对象可以访问。

应用场景:想控制实例数目,节省系统资源的时候。Vue里的Render渲染器。

实现方式:饿汉式(一上来就实例化)和懒汉式(等到需要使用的时候才实例化)

class Singleton {
  constructor() {}
}

Singleton.getInstance = (function() {
  let instance
  return function() {
    if (!instance) {
      instance = new Singleton()
    }
    return instance
  }
})()

let s1 = Singleton.getInstance()
let s2 = Singleton.getInstance()
console.log(s1 === s2) // true

工厂模式

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

作用:创建实例的复杂度,只需要提供一个接口,简单清晰。

应用场景:需要批量创建对象时

class Man {
  constructor(name) {
    this.name = name
  }
  alertName() {
    alert(this.name)
  }
}

class Factory {
  static create(name) {
    return new Man(name)
  }
}

Factory.create('cxk').alertName()

代理模式

概念:代理模式是为了控制对对象的访问,不让外部直接访问到对象。

作用:转发请求,避免直接操作对象

应用场景:比如你需要买一件国外的产品,这时候你可以通过代购来购买产品。比如事件代理就用到了代理模式。Vue的数据劫持就应用了代理模式。

/* 事件代理 */
<ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
<script>
    let ul = document.querySelector('#ul')
    ul.addEventListener('click', (event) => {
        console.log(event.target);
    })
</script>

/* 对象代理 */
var girl = function (name) {
    this.name = name;
};
// 委托人
var man = function (girl) {
    this.girl = girl;
    this.sendGift = function (gift) {
        alert("Hi " + girl.name + ", dudu送你一个礼物:" + gift);
    }
};
// 代理人
var proxyMan = function (girl) {
    this.girl = girl;
    this.sendGift = function (gift) {
        (new dudu(girl)).sendGift(gift); // 替dudu送花咯
    }
};

// 进行代理
var proxy = new proxyMan(new girl("酸奶小妹"));
proxy.sendGift("999朵玫瑰");

发布-订阅模式

概念:发布-订阅模式也叫做观察者模式。通过一对一或者一对多的依赖关系,当对象发生改变时,订阅方都会收到通知。

作用:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

应用场景:在 Vue 中,如何实现响应式也是使用了该模式。对于需要实现响应式的对象来说,在 get 的时候会进行依赖收集,当改变了对象的属性时,就会触发派发更新。

//发布者
class Publisher() {
    construct() {
       this.observers = [] 
    }
    //添加订阅者
    add(oberver) {
         this.observers.push(observer)
    }
  // 通知所有订阅者
    notify() {
      this.observers.forEach((observer) => {
       //调用订阅者的函数
        observer.update(this) 
      })
    }
}
// 订阅者类 顾客
class Observer {
    constructor() {
    }
    update() {
        console.log('Observer  buy buy buy')
    }
}

const cunstomer = new Observer() //创建订阅者:顾客
const amazon = new Publisher() 
amazon.add(cunstomer) //订阅到货小修消息
amazon.notify() //货物到达通知顾客

外观模式

概念:外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。

作用:降低访问复杂系统的内部子系统时的复杂度,简化客户端之间的接口。

应用场景:兼容浏览器添加事件的方法

function addEvent(elm, evType, fn, useCapture) {
  if (elm.addEventListener) {
    elm.addEventListener(evType, fn, useCapture)
    return true
  } else if (elm.attachEvent) {
    var r = elm.attachEvent("on" + evType, fn)
    return r
  } else {
    elm["on" + evType] = fn
  }
}

装饰器模式

概念:给对象动态地增加职责的方式称为装饰器(decorator)模式

作用:在不改变对象自身代码的前提下,新增功能的模式。

应用场景:当我们接手老代码,需要对它已有的功能做个拓展。我们经常需要给手机戴个保护套防摔一样,不改变手机自身,给手机添加了保护套提供防摔功能。

var horribleCode = function(){
  console.log(’我是一堆你看不懂的老逻辑')

}

var _horribleCode = horribleCode

horribleCode = function() {

    _horribleCode()
    console.log('我是新的逻辑')

}

horribleCode()

适配器模式

概念:不需要改变已有的接口,通过包装一层的方式实现两个接口的正常协作。

作用:适配器模式的作用是解决两个软件实体间的接口不兼容的问题。

应用场景:使用适配器模式之后,原本由于接口不兼容而不能工作的两个软件实体可以一起工作。比如Type-C和苹果的转接口。

class Plug {
  getName() {
    return '港版插头'
  }
}

class Target {
  constructor() {
    this.plug = new Plug()
  }
  getName() {
    return this.plug.getName() + ' 适配器转二脚插头'
  }
}

let target = new Target()
target.getName() // 港版插头 适配器转二脚插头

时间戳转换为标准时间就是属于适配器模式

策略模式

概念:策略模式定义一系列的操作类型,把它们一个个封装起来, 并且使它们可相互替换。

作用:解决大量的if-else场景

const strategy = {
    s(base){
        return base * 5;
    },
    a(base){
        return base * 4;
    },
    b(base){
        return base * 3;
    },
    c(base){
        return base * 2;
    }
}

const getBonus = (base, grade) => strategy[grade](base);

const p1 = getBonus(1000, 's') // 5000
const p1 = getBonus(1000, 'c') // 2000
posted @ 2022-09-02 20:30  FailBetter  阅读(83)  评论(0编辑  收藏  举报