likes
comments
collection

前端有什么设计模式?这也算?分享一下我的理解

作者站长头像
站长
· 阅读数 15

有那么个东西,你可能听过,没看过,但是写过😆 那就是设计模式

不说废话,直接上

先来两个手写常问的:

观察者模式

情况

  • 对象存在一对多关系
  • 被观察的对象改变,所有观察者都会收到信号
  • 目标对象自己执行相关操作 —— 收集、维护观察者

写法

// 目标对象
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()
	//...
}

问题

  1. 调用的方法改名这里也要改
  2. 调用的方法不行这里也不行

写法

function EventEmit (){
	this.events = []
	function on(key, callback){
		// 把 callback 放到 key 对应的回调数组中
	}
	function trigger(key){
		// 依次调用 key 对应的回调数组
	}
}
	

然后业务代码里利用 EventEmit 构造函数构造一个 Emitter 然后 on on on on ... 然后 trigger...

EventEmitter 内部和策略模式里调用策略的类写法有点类似有没有

发布订阅模式 VS 观察者模式

这也是一个常问的点:相同之处:

  1. 都是监听一个事件并执行对应的操作

不同之处:

  • 前者实际操作上是借助了一个代理 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吧
  • 写过但没意识到的 —— 说明你天赋异禀哈哈哈

文中措辞、知识点、格式如有疑问或建议,欢迎评论~你对我很重要~ 🌊如果有所帮助,欢迎点赞关注,一起进步⛵这对我很重要~