直播平台开发中,策略模式和发布订阅模式的使用
什么是设计模式
设计模式是一种可复用的解决方案,用于解决直播平台开发中遇到的常见问题;
通俗的讲 设计模式是一套被反复使用,多数人知晓的,经过分类的,代码设计经验的总结。是在直播平台开发过程中,针对特殊问题/场景的更优的解决方案
怎么用
设计模式的核心操作是去观察直播平台开发整个逻辑里面的变与不变,然后将变与不变分离,达到使变化的部分灵活、不变的地方稳定的目的。
策略模式
它的定义很精简:一个类的行为或其算法可以在运行时更改。我们把它降维到直播平台开发层面,用人话翻译一下就是,运行时我给你这个类的方法传不同的“key”,你这个方法会执行不同的业务逻辑。
细品一下,和if else好像没啥区别?
- 什么时候用:
在某些直播平台开发规范里有这样一条 :超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。
说概念有点干 举个小例子🌰 :
有这样一个场景,在请求某个table数据的时候,后端有时会返回状态码,前端需要根据不同的状态码来展示不同的语句
呃。 一言难尽。。。也不知道当时怎么想的,就硬if else,你好歹用个switch也比这个强啊。那个any类型也就不提了
这样写其实也不是不行,对用户来说,最起码运行不报错,效果也符合预期。但对直播平台开发开发来说,首先代码过于冗余,不易阅读; 其次如果后期要再添加/修改某个状态,我只能继续else if,不利于拓展和维护;
既然不行咱就改改:
const generateStatus = (text: string) => {
switch(text) {
case 'STATUS_OK':
return { styles: globalStyle.suc, text: '运行' };
case 'STATUS_UNKNOWN':
return { styles: globalStyle.info, text: '未知状态' };
case 'STATUS_FAIL':
return { styles: globalStyle.fail, text: '故障', };
case 'STATUS_STOPPED':
return { styles: globalStyle.stop, text: '停止' };
default: return { styles: '', text };
}
};
render: (status: string) => {
const { styles, text } = generateStatus(status);
return (
<span className={styles}>{text}</span>
);
}
感觉好多了。。。
当然,除了用switch这种写法,还可以用上面主要讲的策略模式:
// 1.创建一个对象
const statusData = {
'STATUS_OK': { styles: globalStyle.suc, text: '运行' },
'STATUS_UNKNOWN': { styles: globalStyle.info, text: '未知状态' },
'STATUS_FAIL': { styles: globalStyle.fail, text: '故障' },
'STATUS_STOPPED': { styles: globalStyle.stop, text: '停止', },
};
render: (status: string) => {
return (
<span className={statusData[status]?.styles ?? ''}>{statusData[status]?.text ?? text}</span>
);
}
延伸一下:
这里是把status参数当成key值来拿到对应的数据。但在有些时候,上面这种写法可能不能满足直播平台开发的要求。
这里找不到合适的例子,我把需求魔改一下,比如:当前的status是个对象,且没有具有唯一性的属性,比如:
type IType = 'uproxy' | 'ushard';
type ICode = 'STATUS_OK' | 'STATUS_UNKNOWN' | 'STATUS_FAIL' | 'STATUS_STOPPED'
render: (status: {
type: IType,
code: ICode,
}) => {
//....比如这种情况;
};
// 这种情况下也可以用map来实现 (map和object的区别是map可以 value: value);
const statusData = new Map([
[{type: 'uproxy', code: 'STATUS_OK'}, {styles: globalStyle.suc, text: 'uproxy运行'}];
[{type: 'ushard', code: 'STATUS_OK'}, {styles: globalStyle.suc, text: 'ushard运行'}];
])
render: (status) => {
const statusData = [...statusData].find(([key,value]) =>
key.type === status.type && key.code === status.code
);
return (
<span className={statusData[1].styles}>{statusData[1].text}</span>
);
}
总结:
直播平台开发使用策略模式的优点是将一个个逻辑封装起来,并可以任意的替换。在逻辑较多的场景下,代码比直接if else好维护些;
但从上面的例子也可以看出,即使用了策略模式,该写的逻辑还是要写,并不能减少很多的代码量,并且策略越多,拆分组合的过程就会越复杂,所以在使用过程中要合理运用。针对直播平台开发不同的场景,选择合适的解决方案。
发布订阅模式
发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
不知道大家有没有发现,项目里的eventEmitter就是通过发布-订阅模式来实现的,下面是我从项目里粘贴的代码
class EventEmitter {
constructor() {
this.events = {}; //事件存储中心;
this.addListener.bind(this);
this.removeListener.bind(this);
this.emit.bind(this);
}
protected events: {[key: string]: any};
public addListener(event: string, listener: (...args: any[]) => void) {
// 由于一个事件可能注册多个回调函数,所以使用数组来存储事件队列
(this.events[event] || (this.events[event] = [])).push(listener);
}
public removeListener(event: string, listener: (...args: any[]) => void) {
if (this.events[event]) {
this.events[event].splice(this.events[event].indexOf(listener), 1);
}
}
//发布事件。 args 用于收集发布事件时传递的参数
public emit(event: string, ...args: any[]) {
if (this.events[event]) {
this.events[event].forEach((listener: any) => {
listener(...args);
});
}
}
}
const eventEmitter = new EventEmitter();
export default eventEmitter;
要使用的话也很简单,类似于js的addEventListener和removeEventListener;
🌰 : 在直播平台开发某些场景下我们需要监听一下localstorate的变化,但是js原生并没有这样的api来达到我们的目的。我们可以把localstorage的setItem方法重新给封装一下,然后通过EventEmitter来监听localStorage的变化;
//1.设置监听
React.useEffect(() => {
eventEmitter.addListener('storageEvent', handleStorageChange);
return () => {
eventEmitter.removeListener('storageEvent', handleStorageChange);
};
}, []);
//2.封装一个自定义的localStorage的setItem的方法;
//每次在localStorage中写入/修改数据的时候都会调用emit函数发布事件,并把key,value给传递过去;
const setItem = (key, value) {
eventEmitter.emit('storageEvent', {key, value});
return localStorage.setItem(key, value);
}
以上便是“直播平台开发中,策略模式和发布订阅模式的使用”的全部内容,希望对大家由帮助。
因篇幅问题不能全部显示,请点此查看更多更全内容