开放-封闭原则:对扩展开放,对修改封闭。可以扩展新的功能,但是现有功能保持原子性不可修改,保证功能稳定性
组件结构设计、API 设计、数据结构设计
用工厂函数创建实例,隐藏new及参数的处理逻辑封装
- 比如jquery的
$
函数 - React中的
createElement
函数创建 VNode
只能创建全局唯一实例,无法创建第二个
- 比如
Vuex
、Redux
中的store,全局唯一。 - 全局唯一的
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这种多线程语言中,要考虑锁死线程,因为多线程共享进程内存,如果多个线程同时创建,会出现重复问题。
使用者不能直接访问对象,而是访问一个代理层,在代理层可以进行监听拦截进行很多逻辑处理
- Vue3中使用
proxy
代理实现数据响应式
一个主题,一个观察者,主题变化之后触发观察者执行。解决了主题对象与观察者之间的耦合关系。
- 比如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()
发布者和订阅者完全解耦,发布者不需要关心订阅者的操作,只需要发布消息,订阅者收到消息后进行的操作与发布者无关。而且可以进行类型筛选,订阅者可以订阅不同类型的消息。
- vue组件通讯中通过自定义事件数据传递和事件执行
- 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 面向切面编程
- js和ts中的
Decorator
语法 - 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