0 设计模式分类
- 创建型:帮助创建对象(工厂模式、单例模式、建造者模式、原型模式)
- 结构型:帮助设计代码结构(适配器模式、装饰者模式、享元模式)
- 行为型:帮助组织模块行为(策略模式、职责链模式、命令模式)
- 技巧型:优化代码的技巧
1 策略模式
需求:用户管理和组织管理中存在相同的处理操作:创建、编辑、详情,针对编辑和详情,对于不同字段又有不同的处理方式,导致最后写了很多if else,那为什么不能复用,写一段可维护的代码?
export const processDefaultValueFn = {create: () => {},update: () => {},detail: () => {}
}export updateCaseFn = {string: () => {},boolean: () => {}
}
2 适配器模式
需求:组件数据来源由原来的单一来源改为多个接口来源,但原有接口无法改变,因此需要适配,在项目中,我们大多都是单一数据源
3 单例模式
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点
例子:采用单例模式创建dom元素
//单一职责原则,该函数只用于创建DOM元素,不关注创建的DOM元素是什么,将创建DOM元素的内容代理至外部函数中
const createDOM = function(fn) {var resultreturn function() {return result || (fn.apply(this, arguments)) }
}const createDiv = function (){return div
}const createSpan = function(){return span
}createDOM(createDiv)
createDOM(createSpan)
4 代理模式
用法:当不方便访问一个对象时,提供一个代理对象来控制对这个对象的访问
缓存代理:例如useMemo
5 发布-订阅模式
例如:登陆后需要进行一系列设置,导致后续有业务需要添加在登录成功后的函数中,需要加代码
通常写法:
login.success(()=>{header.setAvatar(data)nav.setAvatar()
})
改进写法:
$.ajax('',()=>{login.trigger(data)
})//各模块监听登录成功的消息
const header = (()=>{login.listen('success',(data) => {header.setAvatar(data)})
})()
6 命令模式
应用场景:有些时候需要向某个对象发送请求,但是不知道请求的接收者是谁,请求的操作是什么。通过命令模式解耦请求发送者和请求接收者之间的联系
优点:
- 发布者和接收者之间解耦
- 可以使用栈来维护一个请求队列,从而实现撤销、连续点击等功能
缺点:
- 额外增加一个命令对象,使得代码变得复杂
7 组合模式
分析:创建一颗命令树,每个树的叶子节点包含一个execute方法,js中实现组合模式的难点在于必须保证组合对象和叶对象拥有相同的方法
缺点:树的结果如果比较复杂,性能会受到影响,可以采用职责链模式避免遍历整棵树
应用场景:表示对象的部分-整体结构,统一对待树中的所有对象
8 享元模式(用于性能优化,时间换空间)
该模式要求将对象的属性划分为内部属性和外部属性
- 内部属性:存储于对象内部,可以被一些对象共享,独立于具体场景,不会改变
- 外部属性:取决于具体场景,并根据场景变化,不能共享
应用场景:多文件上传优化
适用场景:
- 使用大量对象造成很大的内存开销
- 对象的大多数状态可以转换成外部状态
使用闭包来私有化对象
const uploadFactory = function() {const obj = {}return {create: function(type) {if (obj[type]) {return obj[type]}return obj[type] = new Upload(type)} }
}
9 中介者模式
其实就是发布-订阅模式
应用场景:对象之间的耦合性太高,更改一个对象后还需更改另一个对象,中介者模式使对象之间的关系解耦
缺点:中介者对象可能会非常复杂
10 装饰器模式
给某个对象动态添加某个功能,并且不影响使用这个对象的其他对象