超级简单的设计模式,看不懂你来打我

简介: 超级简单的设计模式,看不懂你来打我

今天介绍几个经常被提到的设计模式,通俗易懂,包教包会 源码点击这里

单例模式

单例模式的精髓就是不管一个构造函数被实例化多少次,全局只有一个实例

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 我知道我该更新了

如果Observerupdate方法里是跟新对应的dom,那恭喜你,这和vue的基思路理是一样的了

发布/订阅模式

虽然观察者模式可以轻松实现发布订阅模式的功能,但是观察者模式使得concreteSujectconcreteObservver耦合在了一起,对于复杂的系统,解耦才能算得上是优秀的系统。

发布/订阅者模式(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

好了,今天先分享到这里了,欢迎指正

相关文章
|
6月前
|
设计模式 新零售 Java
设计模式最佳套路5 —— 愉快地使用工厂方法模式
工厂模式一般配合策略模式一起使用,当系统中有多种产品(策略),且每种产品有多个实例时,此时适合使用工厂模式:每种产品对应的工厂提供该产品不同实例的创建功能,从而避免调用方和产品创建逻辑的耦合,完美符合迪米特法则(最少知道原则)。
92 6
|
7月前
|
设计模式 算法 架构师
【搞懂设计模式】设计模式与面向对象原则
【搞懂设计模式】设计模式与面向对象原则
77 1
|
设计模式 SQL NoSQL
【设计模式】通俗易懂的Java设计模式篇!1
【设计模式】通俗易懂的Java设计模式篇!
|
设计模式 前端开发 Java
【设计模式】通俗易懂的Java设计模式篇!2
【设计模式】通俗易懂的Java设计模式篇!
|
设计模式 存储 SQL
【设计模式】通俗易懂的Java设计模式篇!3
【设计模式】通俗易懂的Java设计模式篇!
|
设计模式 Java
【设计模式】我终于读懂了装饰者模式。。。(下)
【设计模式】我终于读懂了装饰者模式。。。(下)
【设计模式】我终于读懂了装饰者模式。。。(下)
|
设计模式 关系型数据库
【设计模式】我终于读懂了装饰者模式。。。(上)
【设计模式】我终于读懂了装饰者模式。。。
【设计模式】我终于读懂了装饰者模式。。。(上)
|
设计模式 存储 算法
三天肝完设计模式的面试题,面试再不怕设计模式的问题了
设计模式是面试的重头戏,面试必考必问。
184 0
|
设计模式 算法 前端开发
什么是设计模式?程序员如何学好设计模式?
许多前辈程序员经过长期实践,总结出了一系列的解决方案。这些解决方案可以提高代码的可读性,增加代码的可重用性,保证代码的可扩展性。 这一系列解决方案,被人们称为设计模式,它是面向对象编程当中的各种经典套路。 设计模式是一种抽象的编程思想,并不局限于某一特定的编程语言,而是在许多语言之间相通的。比如在Java、C#、C++语言当中,都可以使用到设计模式。
406 1
|
设计模式 关系型数据库 MySQL
平时代码中用不到设计模式?Are you kidding me?
引子 平时我是个反应非常慢的人。有多慢呢?大概是两年前有次团队内部开会时,我听到同学说平时代码中用不到设计模式,我当时没有回答。两年后我终于反应过来了:“Are you kidding me?我每天都在用!”
平时代码中用不到设计模式?Are you kidding me?

热门文章

最新文章