Skip to content

Latest commit

 

History

History
219 lines (161 loc) · 5.24 KB

常见设计模式及应用场景.md

File metadata and controls

219 lines (161 loc) · 5.24 KB

设计原则

开放-封闭原则:对扩展开放,对修改封闭。可以扩展新的功能,但是现有功能保持原子性不可修改,保证功能稳定性

何为技术方案设计

组件结构设计、API 设计、数据结构设计

工厂模式

用工厂函数创建实例,隐藏new及参数的处理逻辑封装

  1. 比如jquery的$函数
  2. React中的createElement函数创建 VNode

单例模式

只能创建全局唯一实例,无法创建第二个

  1. 比如VuexRedux中的store,全局唯一。
  2. 全局唯一的Dialog modal弹层
class Factory{
    private constructor(){}
    private static factory:Factory = new Factory() 
    public static getFactory():Factory{
        return this.factory
    }
    fn1(){}
}

const f1 = Factory.getFactory()
const f2 = Factory.getFactory()
console.log(f1 === f2) // true

js 一般是单线程执行的,创建单例不会存在重复问题。但如果在类似java这种多线程语言中,要考虑锁死线程,因为多线程共享进程内存,如果多个线程同时创建,会出现重复问题。

代理模式

使用者不能直接访问对象,而是访问一个代理层,在代理层可以进行监听拦截进行很多逻辑处理

  1. Vue3中使用proxy代理实现数据响应式

观察者模式

一个主题,一个观察者,主题变化之后触发观察者执行。解决了主题对象与观察者之间的耦合关系。

  1. 比如dom监听,一个dom可以添加很多监听函数,dom改变时可以通过触发动作执行回调函数
<button id='btn'></button>
<script>
    btn.addEventListener('click', ()=>{...})
</script>

观察者模式的实现

class Subject {
    constructor(){
        this.observers = []
    }
    add(...observer){
        this.observers = this.observers.concat(observer)
    }
    remove(...observer){
        this.observers = this.observers.filter(item => !observer.includes(item))
    }
    notify(){
        this.observers.forEach(observer => {
            observer.update()
        })
    }
}
class Observer {
    constructor(name){
        this.name = name
    }
    update(){
        console.log('update',this.name)
    }
}

const subject = new Subject()
const observer1 = new Observer('flten')
const observer2 = new Observer('wall')

subject.add(observer1,observer2)
subject.remove(observer1)
subject.notify()

发布订阅模式

发布者和订阅者完全解耦,发布者不需要关心订阅者的操作,只需要发布消息,订阅者收到消息后进行的操作与发布者无关。而且可以进行类型筛选,订阅者可以订阅不同类型的消息。

  1. vue组件通讯中通过自定义事件数据传递和事件执行
  2. EventBus

注意:vue中绑定的事件要用独立函数绑定,要及时解绑事件,防止内存泄漏。例如mounted中绑定,beforeUnmount中解除绑定

与观察者模式的区别:

观察者模式中的主题和观察者是直接绑定一起出现的,发布订阅模式中需要收集订阅的事件,然后统一发布

发布订阅的实现:

class pubSub {
    constructor(){
        this.sub = {}
    }
    subscribe(type, cb){
        this.sub[type] ? this.sub[type].push(cb) : this.sub[type] = [cb]
    }
    unsubscribe(type, cb){
        if(!this.sub[type]) return;
        !cb ? this.sub[type] = [] : this.sub[type].filter(item => item !== cb)
    }
    publish(type, data){
        if(!this.sub[type]) return;
        this.sub[type].forEach(cb => {
            cb(data)
        });
    }
}

const sub = new pubSub()
const fn1 = (data) => console.log('a',data)
const fn2 = (data) => console.log('b',data)

sub.subscribe('a',fn1)
sub.subscribe('a',fn2)
sub.subscribe('b',fn1)
sub.subscribe('b',fn2)

sub.publish('a',1111)
sub.publish('b',2222)

sub.unsubscribe('a',fn1)
console.log(sub)
sub.unsubscribe('b')
console.log(sub)

装饰器模式

原来的功能不变,增加新的功能,即 AOP 面向切面编程

  1. js和ts中的Decorator语法
  2. nestjs 中的路由装饰器

理解装饰者模式:

下面的代码中,fn2使用了fn1,但没有改变fn1,而增加了新的功能,这符合开放-封闭原则,这就是装饰者模式的最简化。

function fn1(){
    console.log('fn1')
}

function fn2(){
    fn1()
    console.log('fn2')
}
fn2()

策略模式

解决if-else逻辑复杂,代码分支多的情况。不然每多一种情况,就要破坏原来的if结构体,增加或删除逻辑

下面的代码中,就是将不同的策略进行了抽离,对该策略对象进行维护即可。

const strategy = {
    basement(books){
        return books
    },
    high(books){
        return books * 2
    },
    university(books){
        return books * 3
    },
} 

function showLevel(level, books){
    return strategy[level](books)
}

console.log(showLevel('high', 10)) // 20

反观如果使用if-else,代码结构会看起来很混乱:

function showLevel(level, books){
    if(level === 'basement'){
        return books
    }else if(level === 'high'){
        return books * 2
    }else if(level === 'university'){
        return books * 3
    }
}

console.log(showLevel('high', 10)) // 20