js 几种常用的设计模式

这是我参与更文挑战的第11天,活动详情查看: 更文挑战

写在前面

这几天在学一下设计模式,虽然说前端是写页面,做切图仔(调侃一下),但是也有很大部分时候是写逻辑的,下面我把常用的设计模式总结一下,正所谓工欲善其事必先利其器, 如果我们能在代码中使用到一些设计模式,对我们代码的优化还是有很大帮助的。

设计模式

单体模式

单体模式,就是指一个类内部只实例化一个实例,不管你使用这个类创建几个实例,这几个实例返回的都是同一个实例。

class singleMode {
    constructor(name) {
        this.name = name
    }
    getName () {
       return this.name
    }
    getInstance () {
       return this
    }
}
createSingleMode = (function () {
  let singleModeInstance
  return function (name) {
   if (!singleModeInstance) singleModeInstance = new singleMode(name)
   return singleModeInstance
  }
})()
const singleMode1 = new createSingleMode('答案cp3')
const singleMode2 = new createSingleMode('答案cp3')
console.log(singleMode1 === singleMode2) // true
console.log(singleMode1.getInstance() === singleMode2.getInstance()) // true
console.log(singleMode1.getName()) // 答案cp3
console.log(singleMode2.getName()) // 答案cp3
复制代码

从以上代码可以看到,如果创建过实例,则不需再创建,直接返回,所以返回的实例是相等的,是同一个实例。

工厂模式

工厂模式,在内部将创建具体对象的过程操作单独封装,不对外暴露出来。

function Factory (name) {
   const obj = {}
   obj.name = name
   obj.getName = function () {
    return this.name
   }
   return obj
}
const factory1 = new Factory('答案')
const factory2 = new Factory('cp3')
console.log(factory1.getName()) // 答案
console.log(factory2.getName()) // cp3
复制代码

上面代码中obj就是在函数Factory内部创建,并且赋值方法,属性等。

策略模式

定义好需要的策略,然后根据传入的策略名去执行对应的策略。
比如你想开通会员,有青铜会员白银会员黄金会员,开通会员后对应的商品折扣是不同的,这时候就可以用上策略模式。

const memberType = {
  copper: function (price) {
    return  price * 0.9
  },
  silver: function (price) {
    return  price * 0.7
  },
  gold: function (price) {
    return price * 0.5
  }
}
memberType['copper'](100) // 打折后 90
memberType['silver'](100) // 打折后 70
memberType['gold'](100)   // 打折后 50

复制代码

根据身份定好折扣,传入身份和价格,就知道打折后是多少,这种策略模式可读性强,维护性好,不需要写多余的ifelse

代理模式

给目标对象设置一个代理,不直接暴露目标对象。

// 为这个target设置一个代理
class Target {
   constructor (name) {
    this.name = name
   }
   getName () {
    return this.name
  }
}
// 代理
class ProxyTarget {
  constructor (name) {
      this.target = new Target(name)
  }
  getName () {
    return this.target.getName()
  }
}
const proxy = new ProxyTarget('答案cp3')
proxy.getName() // 答案cp3
复制代码

以上就是给Target对象设置一个ProxyTarget,外界不能直接访问到Target

装饰器模式

装饰器模式就是在不改变对象自身的基础上,给对象添加新方法,同时旧方法也还在

class Circle {
    draw() {
        console.log('先画一个圆形')
    }
}
// 装饰器
class DecoratorMode {
    constructor(circle) {
        this.circle = circle
    }
    draw() {
        this.circle.draw()
        this.setRedBg(this.circle)
    }
    setRedBg(circle) {
        console.log('再设置红色背景')
    }
}

let circle = new Circle()
let decorator = new DecoratorMode(circle); // 把circle实例传入
decorator.draw();  // 先画一个圆形,再设置红色背景
复制代码

上面代码中,装饰器模式在对象的draw方法额外加上了setRedBg方法

发布-订阅模式

发布-订阅模式其实是1对N的关系,订阅者先把自己把事件订阅到调度台,然后发布者发布该事件到调度台,调度台调用该事件对应的函数。 vue2.0内部的Vue watch等就是利用这个模式

// 构造函数,调度台
function Publish () {
  this.subObj = {}
}
// 订阅者
Publish.prototype.on = function(name, fn) {
 if(this.subObj[name]) {
   this.subObj[name].push(fn)
 } else this.subObj[name] = [fn]
}
// 发布者
Publish.prototype.emit = function (name, data) {
  if (this.subObj[name]) {
      for(let i = 0; i < this.subObj[name].length; i++) {
         this.subObj[name][i](data)
      }
  }
}
Publish.prototype.off = function (name, fn) {
  if (this.subObj[name]) {
      if(fn) {
         for(let i = 0; i < this.subObj[name].length; i++) {
            if(this.subObj[name][i] === fn) {
              this.subObj[name].splice(i,1)
            }
         }
      } else {
        delete this.subObj[name]
      }
  }
}

const a = new Publish()
const fn1 = () => {
 console.log('fn1')
}
const fn2 = () => {
 console.log('fn2')
}
a.on('aaa', fn1) // 订阅 fn1
a.on('aaa', fn2) // 订阅 fn2
a.emit('aaa') // 输出 fn1 和 fn2

a.off('aaa', fn1) // 取消订阅
a.emit('aaa') // 只输出 fn2

复制代码

总结

以上就是最近学到的几种常用的设计模式的总结,希望对你们能有帮助。一起加油~

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享