超级简单的设计模式,看不懂你来打我
未经允许禁止转载
今天介绍几个经常被提到的设计模式,通俗易懂,包教包会
源码点击这里
单例模式
单例模式的精髓就是不管一个构造函数被实例化多少次,全局只有一个实例
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
属性发生变化时,都会对应的观察者会接受到变化
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
好了,今天先分享到这里了,欢迎指正