这是我参与更文挑战的第11天,活动详情查看: 更文挑战
写在前面
这几天在学一下设计模式,虽然说前端是写页面,做切图仔(调侃一下),但是也有很大部分时候是写逻辑的,下面我把常用的设计模式总结一下,正所谓工欲善其事必先利其器, 如果我们能在代码中使用到一些设计模式,对我们代码的优化还是有很大帮助的。
设计模式
发布-订阅模式
发布-订阅模式其实是1对多的关系,订阅者先把事件订阅到调度中心,然后发布者需要执行哪个事件,就把该事件的名称发到调度中心,调度中心则调用该事件对应的函数。 vue2.0的内部很多实现就是利用这个模式
// 订阅-发布模式-简易版
class Publish {
constructor () {
// 调度中心
this.subObj = {}
}
// 订阅者
on (name, fn) {
if (this.subObj[name]) {
this.subObj[name].push(fn)
} else this.subObj[name] = [fn]
}
// 发布者
emit (name, data) {
if (this.subObj[name]) {
for (let i = 0; i < this.subObj[name].length; i++) {
this.subObj[name][i](data)
}
}
}
// 取消订阅
off (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
发布-订阅模式中发布者和订阅者是没有关联的,完全是调度中心去管理,这样处理,灵活度高,易扩展;
观察者模式
观察者模式和发布-订阅模式很像,但是区别是它没有调度中心,他是主要2种角色,目标对象和观察者,观察者把自己的函数方法添加到目标对象里,当目标对象触发的时候,依次执行所有观察者对应的方法。
// 观察者模式
// 目标对象
class Target {
constructor () {
this.observers = []
}
add (obverser) {
this.observers.push(obverser)
}
notify () {
for (let i = 0; i < this.observers.length; i++) {
this.observers[i].update()
}
}
}
// 观察者
class Observer {
constructor () {
}
update () {
console.log('我被调用了')
}
}
// 目标对象
const target = new Target()
// 观察者1
const observer1 = new Observer()
// 观察者2
const observer2 = new Observer()
target.add(observer1)
target.add(observer2)
// 通知
target.notify()
// 我被调用了
// 我被调用了
观察者模式没有有发布-订阅那么灵活,它需要目标对象和观察者耦合在一起,而且目标对象不知道哪个观察者是哪个,触发的时候只能通知所有观察者。
单体模式
单体模式,就是指一个类内部只实例化一个实例,不管你使用这个类创建几个实例,这几个实例返回的都是同一个实例。
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
根据身份定好折扣,传入身份和价格,就知道打折后是多少,这种策略模式可读性强,维护性好,不需要写多余的if和else。
代理模式
给目标对象设置一个代理,不直接调用目标对象。
// 为这个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方法
总结
以上就是最近学到的几种常用的设计模式的总结,希望对你们能有帮助。一起加油~