前端有什么设计模式?这也算?分享一下我的理解
有那么个东西,你可能听过,没看过,但是写过😆 那就是设计模式
不说废话,直接上
先来两个手写常问的:
观察者模式
情况
- 对象存在一对多关系
- 被观察的对象改变,所有观察者都会收到信号
- 目标对象自己执行相关操作 —— 收集、维护观察者
写法
// 目标对象
class Subject {
constructor() {
this.observers = [];
}
add(observer) {
this.observers.push(observer);
}
notify() {
this.observers.map(observer => {
observer?.callback();
});
}
remove(observer) {
this.observers = this.observers.filter(o => o !== observer);
}
}
class Observer {
constructor(id) {
this.id = id;
}
callback() {
console.log('id:', this.id);
}
}
const subject = new Subject();
const o1 = new Observer(1);
const o2 = new Observer(2);
subject.add(o1);
subject.add(o2);
subject.notify(); //id:1 id:2
subject.remove(o1);
subject.notify(); //id:2
发布订阅模式
情况
- 一个点触发多处地方逻辑
- 模块相互独立
- 依赖关系不稳定
不采用发布订阅模式
function a(){
b1()
b2()
b3()
b4()
b5()
b6()
//...
}
问题
- 调用的方法改名这里也要改
- 调用的方法不行这里也不行
写法
function EventEmit (){
this.events = []
function on(key, callback){
// 把 callback 放到 key 对应的回调数组中
}
function trigger(key){
// 依次调用 key 对应的回调数组
}
}
然后业务代码里利用 EventEmit 构造函数构造一个 Emitter 然后 on on on on ... 然后 trigger...
EventEmitter 内部和策略模式里调用策略的类写法有点类似有没有
发布订阅模式 VS 观察者模式
这也是一个常问的点:相同之处:
- 都是监听一个事件并执行对应的操作
不同之处:
- 前者实际操作上是借助了一个代理 Event 对象;后者都是发布者 —— 即目标对象自身维护观察者和消息的发布
- 前者订阅发布两者不需要知道对方的存在,解耦度更高
就是前者有个菜鸟驿站,后者包邮到家
策略模式
情况
- 很多判断条件
- 判断条件策略相互独立
- 判断条件可复用
- 策略内部复杂 —— 如果直接暴力写会有很多 if else
- 策略可能还会变化
->比如表单验证
写法
// 统一管理各个策略
const strategies = ()=>{
check1 : function check1(){}
check2 : function check2(){}
check3 : function check3(){}
}
// 调配策略的对象
function Checker(){
this.checks = []
this.add = function(value, method){
// 将检验函数加入 checks
}
this.check = function(){
//依次调用 checks 中的 check
}
}
使用
const checker = new Checker()
checker.add(/*... */)
checker.add(/*... */)
const flag = checker.check()
if(flag){
//...
}
代理模式
情况
- 模块单一可复用
- 模块之间交互需要限制
写法
有一个本体,再来一个对本体的代理
// 本体
const a = () =>{
//干点事情
}
//代理
const proxyA = () =>{
// 干点预处理啥的?
if(flag) a() //满足条件才干?
// 收下尾?
执行具体功能的还是 本体 a,但是一些预处理什么的,控制做不做,就看代理了
责任链模式
之前写的 koa-compose也有提到~
情况
- 一连串的处理
- 多个处理之间相关,或者说有要求执行顺序
- 可能会修改处理,比如增删改
如果你是一个个调用...获取结果,将结果作为参数传入下一个方法中并执行... 这太耦合了。
责任链模式就是为了比卖你发送者与多个请求处理者耦合在一起,一次次调用实在丑陋不如直接通过预处理,让每一个操作都能自己连接下一个操作 —— 记住下一个方法的引用 —— 形成一条链,处理就沿着这条链传递
写法
各种有中间件的库 ,都会有这个玩意 compose ~ 建议没看过的看一下
可以看这里koa-composecompose 源码解析
这里给个简单的 compose ,redux 里就是这样,
mini-redux 看这里 mini-redux 欢迎 start ⭐
function compose(fns){
return fns.reduce((a,b)=> (...args)=>a(b(...args)))
有新需求?
fns.push()
剩下两个简单多,就随便讲讲
装饰器模式
这个比较简单装饰,顾名思义,装饰一下原先的东西 —— 就是 强化呗比如 封装一个组件,或者说 React 的高阶组件,升级传入的组件也就是传入一个旧的东东,传出一个新的东东,新的东西拥有更强的技能
装饰器模式 VS 代理模式
乍一看,和代理模式 有那么一点点相似噢。都是给本体和新类实现了一样的接口,然后执行具体操作都是在新类中调用本体
- 前者强调增强本身功能,后者强调控制访问
- 前者的功能你很需要,后者你可能本身并不关心的、业务联系不大的职责 —— 记录日志、设置缓存
- 前者有点像 子类继承父类再扩展,后者只是控制本体的引用
- 扩展之后使用子类,父类是没变化的;后者操作之后本体是变化了的
适配器模式
适配,这个词代表啥意思,兼容!就是把原来不怎么好用或者说用不了的东西,封装一下,让他变成我们想要的
就比如不同类的参数接口,举一个简单的例子,比如一个 展示头像的组件,它只需要 头像的链接 —— avatar 一个 string 类型但是传入的个人信息里面,一大串,什么名字、ID、简介、年龄,你需要吗,不需要。可能你要的 avatar ,他也没有,他不叫 avatar ,他叫 touxiang 或者 portrait你怎么样,把他转换了呗
总结
其实这些个设计模式大家写代码的时候 应该都有在你没意识到的时候使用了,尤其后面的装饰器、适配器模式,看完后有没有一种,
啊?这也算“设计模式”啊
的感觉
是吧,我觉得设计模式有时就像潜移默化的习惯,不是一种生搬硬套,而是思想。他没有多高端,他就在我们日常敲代码中
- 之前没这样写过的,去 try try吧
- 写过但没意识到的 —— 说明你天赋异禀哈哈哈
文中措辞、知识点、格式如有疑问或建议,欢迎评论~你对我很重要~ 🌊如果有所帮助,欢迎点赞关注,一起进步⛵这对我很重要~
转载自:https://juejin.cn/post/7160204115186810910