设计模式

1,345 阅读3分钟

1. 单例模式

一个类只能创建一个实例。代码实现思路:先判断是否创建实例,创建过直接返回,没有则创建实例,并返回

class Person {
    constructor (name) {
        this.name = name
    }
}
Person.getInstance = function (name) {
    if (this.instance) {
        return this.instance
    }else {
        return this.instance = new Person(name)
    }
}

作用: 模块之前的通信、保证某个类唯一实例

应用场景:

  • 点击某个button,弹出登录框,每次点击只能弹出一个

代码实现

style:

.loginLayer {// 登录框的样式 }

html:

<button id='btn'>登录</button>

js:

class LoginLayer {
    constructor () {
      this.instance = null
      this.init()
    }
    init () {
      let ele = document.createElement('div')
      ele.classList.add('loginLayer')
      ele.innerHTML = "登录弹框"
      document.body.appendChild(ele)
    }
    static getInstance () {
      if (this.instance) return this.instance
      this.instance = new LoginLayer()
      return this.instance;
    }
}
let btn = document.getElementById('btn')
btn.addEventListener('click', _ => {
  LoginLayer.getInstance()
}, false)

  • vuex store全局只有一个
function install (_Vue) {
    if (Vue && _Vue === Vue) {
      {
        console.error(
          '[vuex] already installed. Vue.use(Vuex) should be called only once.'
        );
      }
      return
    }
    Vue = _Vue;
    applyMixin(Vue);
  }

2.构造器模式

用于创建特定类型的对象,实现复杂业务逻辑和功能的可复用

  • 创建一个个实例,互不影响
  • 逻辑和功能可复用
class Person {
	construcotr (name) {
    	this.name = name
    }
    getName () {
    	return this.name
    }
}

3. 建造者模式

将复杂的逻辑有条理的一步步拆分实现

4. 代理模式

一个对象通过某种代理方式来控制对另一个对象的访问

作用:

  • 缓存代理 (运算开销比较大的,提供缓存,下次进行相同的计算,不需要在重新计算)
function sum(a, b){
  return a + b
}
let proxySum = function() {
  let cache = {}
  return function () {
    let argStr = Array.prototype.join.call(arguments)
    if (argStr in cache) {
      return cache[argStr]
    }
    cache[argStr] = sum.apply(this, arguments)
    return cache[argStr]
  }
}
  • 安全代理 (限制原对象的访问权限)
  • 虚拟代理 (渲染网页需要的大图,可以先使用缩略图)
var myImage = (function(){
  var imgNode = document.createElement( 'img' );
  document.body.appendChild( imgNode );
  return {
    setSrc: function( src ){
      imgNode.src = src;
    }
  }
})()

// 创建代理对象
var proxyImage = (function(){
  let defaultUrl = '' // 默认图片
  var img = new Image();
  img.onload = function(){
    myImage.setSrc( this.src )
  }
  return {
    setSrc: function( src ){
      myImage.setSrc(defaultUrl)
      img.src = src;
    }
  }
})()

proxyImage.setSrc(url)
  • 远程代理

5.外观模式

外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用

  • 简化复杂接口
  • 解耦和,屏蔽使用者对子系统的直接访问
function a(x){
   // do something
}
function b(y){
   // do something
}
function ab( x, y ){
    a(x);
    b(y);
} 

应用场景

我们可以使用外观模式来设计兼容不同浏览器的事件绑定的方法以及其他需要统一实现接口的方法或者抽象类.


function on(type, fn){
  // 对于支持dom2级事件处理程序
  if(document.addEventListener){
      dom.addEventListener(type,fn,false);
  }else if(dom.attachEvent){
  // 对于IE9一下的ie浏览器
      dom.attachEvent('on'+type,fn);
  }else {
      dom['on'+ type] = fn;
  }
}

6.观察者模式 - VUE

所有观察者监听某个对象,当对象发生变化时,会通知所有的观察者,使得观察者自更新

class Subject {
  constructor () {
    this.subs = []
  }

  addSub (sub) {
    if (this.subs.indexOf(sub) === -1) {
      this.subs.push(sub)
    }
  }

  nodify () {
    this.subs.forEach(sub => sub.update())
  }
}

class Observer {
  constructor (observerName) {
    this.observerName = observerName
  }
  update () {
    console.log(`通知了${this.observerName},状态改变了`)
  }
}

let sub = new Subject()
let o1 = new Observer('o1')
let o2 = new Observer('o2')
sub.addSub(o1)
sub.addSub(o2)

7.发布订阅者模式

属于观察者模式的子集,区别在于,观察模式是观察者依附于被观察者;发布订阅没有,他们有公共的桥梁

let pubsub = {};
(function(pubsub) {
  let callbacks = []
  let results = [] // publisher
  pubsub.publish = function (data) {
      results.push(data)
      callbacks.forEach(c => c(results))
  }

  pubsub.subscribe = function (callback) {
      callbacks.push(callback)
  }
}(pubsub))

pubsub.subscribe((data) => {
  if (data.length === 3) {
      console.log('data长度为3')
  } else {
      console.log('其他数据长度')
  }
})
pubsub.publish(3)
pubsub.publish(3)
pubsub.publish(3)

8. 策略模式

策略模式将不同算法进行合理的分类和单独封装,让不同算法之间可以互相替换而不会影响到算法的使用者

  • 实现不同, 作用一致
  • 调用方式相同,降低了使用成本以及不同算法之间的耦合
  • 单独定义算法模型, 方便单元测试
  • 避免大量冗余的代码判断,比如if else等
const obj = {
  A: (num) => num * 4,
  B: (num) => num * 6,
  C: (num) => num * 8
}

const getSum =function(type, num) {
  return obj[type](num)
}