今天介绍几个经常被提到的设计模式,通俗易懂,包教包会 源码点击这里
单例模式
单例模式的精髓就是不管一个构造函数被实例化多少次,全局只有一个实例
const Singleton = (function () { let instance; function init () { return new Object(); } return function () { if (!instance) { instance = init(); } return instance; } })() let mySingleton1 = new Singltron(); let mySingleton2 = new Singltron(); console.log(mySing1 === mySing2) // true
单例模式的本质就是共享同一个作用域链,很明显这是JavaScript
的闭包
机制实现的
观察者模式
观察者模式主要是通过一个目标(Suject)维护一系列的观察者(Observer),当目标发生变化时,通过广播事件,将目标具体的变化通知所有的观察者
观察者模式主要由四个角色组成:目标(Suject)
、 观察者(Observer)
、具体目标
、具体观察者
下面的例子中,当data
对象的name
或者age
属性发生变化时,都会对应的观察者会接受到变化
作者:萌萌哒草头将军
链接:https://juejin.cn/post/7222575963565375544
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Observer { constructor (code) { this.code = code; } update () { console.log('我是:', this.code, '我知道我该更新了') } } class Suject { constructor () { this.observerList = []; } addObserver (observer) { this.observerList.push(observer) } notify () { this.observerList.map((observer) => observer.update()) } } // 具体的观察者 const concreteObservver1 = new Observer('concreteObservver1'); const concreteObservver2 = new Observer('concreteObservver2'); const concreteObservver3 = new Observer('concreteObservver3'); const concreteObservver4 = new Observer('concreteObservver4'); // 具体的目标 const concreteSuject1 = new Suject(); const concreteSuject2 = new Suject(); // 具体的对应关系 concreteSuject1.addObserver(concreteObservver1); concreteSuject1.addObserver(concreteObservver2); // 具体的对应关系 concreteSuject2.addObserver(concreteObservver3); concreteSuject2.addObserver(concreteObservver4); const data = {name: '萌萌哒草头将军', age: 18} // 当data的name属性变化,对应的观察者concreteObservver1、 // concreteObservver2就会被广播事件通知,从而更新 Object.defineProperty(data, 'name', { get: () => this.name, set: (newValue) => { concreteSuject1.notify(); this.name = newValue; } }) // 当data的age属性变化,对应的观察者concreteObservver3、 // concreteObservver4就会被广播事件通知,从而更新 Object.defineProperty(data, 'age', { get: () => this.age, set: (newValue) => { concreteSuject2.notify(); this.age = newValue; } }) data.name = 'mmdctjj' // 我是: concreteObservver1 我知道我该更新了 // 我是: concreteObservver2 我知道我该更新了 data.age = 18 // 我是: concreteObservver3 我知道我该更新了 // 我是: concreteObservver4 我知道我该更新了
如果Observer
的update
方法里是跟新对应的dom
,那恭喜你,这和vue
的基思路理是一样的了
发布/订阅模式
虽然观察者模式可以轻松实现发布订阅模式的功能,但是观察者模式使得concreteSuject
和concreteObservver
耦合在了一起,对于复杂的系统,解耦才能算得上是优秀的系统。
发布/订阅者模式(Public/Subscribe)
,可以很好的解决观察者模式耦合问题,那么它是怎么解耦的呢?
发布/订阅模式
提供了主题/事件通道(Topic/event Channer)
,,订阅者通过Subscribe
功能和topic
绑定,当发布者发生变化时,将所有的变更通过event
广播给所有订阅该topic
的订阅者们。这样就将发布者和订阅者完全隔离开了
还是上面的例子,我们用发布/订阅模式
实现
class PubSub { constructor() { this.topics = {} this.uuid = 0 // 每个订阅者的唯一标识,可以随时取消订阅 } // 发布器 publish(topic, value) { if (this.topics[topic]) { this.topics[topic].map(({ event }) => event(value)) } } // 订阅器 subscribe(topic, event) { const uuid = this.uuid++ this.topics[topic] = this.topics[topic] ? [...this.topics[topic], { event, uuid }] : [{ event, uuid }] return uuid } } const MyPubSub = (function () { let instance; function init() { return new PubSub(); } return function () { if (!instance) { instance = init(); } return instance; } })() const myPubSub = new MyPubSub() const data = { name: '萌萌哒草头将军', age: 18 } myPubSub.subscribe('data.name', (value) => console.log( '我知道', 'name发生变化了:', value )) myPubSub.subscribe('data.name', (value) => console.log( '我也知道', 'name发生变化了:', value )) myPubSub.subscribe('data.age', (value) => console.log('我知道', 'age发生变化了:', value)) Object.defineProperty(data, 'name', { get: () => this.name, set: (newValue) => { myPubSub.publish('data.name', newValue) this.name = newValue; } }) Object.defineProperty(data, 'age', { get: () => this.age, set: (newValue) => { myPubSub.publish('data.age', newValue) this.age = newValue; } }) data.name = 'mmdctjj' // 我知道 name发生变化了: mmdctjj // 我也知道 name发生变化了: mmdctjj data.age = 18 // 我知道 age发生变化了: 18
jauery
的实现了标准的发布订阅模式
$.trigger('login', {userName: 'MMDCTJJ', password: '*******'}) $.on('login', (userInfo) => console.log(userInfo))
vue
中,可以使用$emit
方法和$on
<button @click="$emit('increaseBy', 1)"> Increase by 1 </button> <MyButton @increase-by="(n) => count += n" />
中介者模式
中介者模式也和观察者类似,中介者模式由中介者
和订阅者
组成 所有的订阅者们不能互相沟通,必须通过中介者同步信息。
const mediator = (function () { let topics = [], uuid = 0; function subscribe (topic, callback) { uuid ++ topics[topic] = topics[topic] ? [...topics[topic], { callback, uuid }] : [{ callback, uuid }] } function publish (topic, value) { if (topics[topic]) { topics[topic].map(item => item.callback(value)) } } return { install: function (obj) { obj.uuid = uuid obj.publish = publish obj.subscribe = subscribe return obj } } })() const subscribe1 = mediator.install({}) const subscribe2 = mediator.install({}) const subscribe3 = mediator.install({}) subscribe1.subscribe('data.name', (value) => console.log('我是subscribe1', value)) subscribe2.subscribe('data.name', (value) => console.log('我是subscribe3', value)) const data = { name: '萌萌哒草头将军', age: 18 } Object.defineProperty(data, 'name', { get: () => this.name, set: (newValue) => { subscribe3.publish('data.name', newValue) this.name = newValue; } }) data.name = 'mmdctjj' // 我是subscribe1 mmdctjj // 我是subscribe3 mmdctjj
策略模式
策略模式可以在不同的时机,采用不同的策略解决开发中的问题
相信你经常遇到同事这样的代码
// bad let arr = [1, 2, 3] arr.map(a => { if (a === 1) { console.log('11') } else if (a === 2) { console.log('22') } else if (a === 3) { console.log('33') } })
这种如果需要优化,可以使用策略模式
class Strategy { constructor() { this.strategy = {} // JavaScript的策略模式可以通过对象来巧妙实现 } addStrategy(name, callback) { this.strategy[name] = callback } execute(name, args) { this.strategy[name]?.(args) } } // good let arr = [1, 2, 3] const strategy = new Strategy() strategy.addStrategy(1, () => console.log(11)) strategy.addStrategy(2, () => console.log(22)) strategy.addStrategy(3, () => console.log(33)) arr.map(a => strategy.execute(a, 'your args'))
装饰器模式
装饰器模式(Decorater)
,主要通过扩展已有的类增加新功能,它不会修改底层代码,是一种对象子类继承的替代方案
class YourClass { constructor () { this.number = 0 } count () { this.number ++ return this.number } } class Decorater { constructor (other) { this.number = other.number + 66 } count () { this.number = this.number + 100 return this.number } } const yourClass = new YourClass() const decorater = new Decorater(yourClass) console.log(yourClass.count(), 'yourClass') // 1 console.log(decorater.count(), 'decorater') // 166 console.log(yourClass.count(), 'yourClass') // 2 console.log(decorater.count(), 'decorater') // 266
好了,今天先分享到这里了,欢迎指正