HarmonyOS Next 浅谈 发布-订阅模式
HarmonyOS Next 浅谈 发布-订阅模式
前言
其实在目前的鸿蒙应用开发中,或者大前端时代、vue、react、小程序等等框架、语言开发中,普通的使用者越来越少的会碰到必须要掌握设计模式的场景。大白话意思就是一些框架封装太好了,使用者只管在它们的体系下使用就行,哪怕不懂设计模式,也不妨碍我们正常开发业务。但是,如果碰到要封装一些工具、或者游戏开发的时候,那么设计模式的重要性就突显出来了。因为在做封装的时候,如果不使用一些设计模式,那么这些封装的代码基本无法使用。有同感的小伙伴可以踊跃发言。😄
目标
arkts 中,存在 Emitter 对象,它具有持续订阅事件和单次订阅事件、取消订阅事件、触发事件的能力。我们可以将它做为封装的参考,来自己实现一个类似的封装。
Emitter 的使用就是典型的发布-订阅的设计模式。也可以理解为(生产者-消费者设计模式)
- 订阅 理解为我们向邮局订阅一些报刊
- 发布 理解为报刊发布了,我们自然会受到对应的新报刊
- 对于订阅者来说
- 我们可以无限时长的订阅报刊(持续订阅)
- 我们可以只订阅一次报刊(单次订阅)
- 可以取消订阅的报刊
- 对于发布者来说
- 负责发布即可
接口设计
方法 | 说明 |
---|---|
on | 持续订阅 |
once | 单词订阅 |
off | 取消订阅 |
emit | 发布 |
具体实现
定义类型
- eventType 定义一个事件类型的联合类型,它可以是 normal 或者 once
- IEventItem 定义一个事件项的接口,包含事件 ID、类型、回调函数数组以及事件具体类型等属性
// 定义一个事件类型的联合类型,它可以是 "normal" 或者 "once"
type eventType = "normal" | "once";
// 定义一个事件项的接口,包含事件ID、类型、回调函数数组以及事件具体类型等属性
interface IEventItem {
eventId: number;
type: string;
cbs: Function[];
eventType: eventType;
}
定义类的基本结构
- MyEmitter 为封装 Emitter 的自定义类的名称
- listeners 存储所有事件监听器的私有静态数组,初始为空
- _eventId 用于生成唯一事件 ID 的私有静态变量,初始值为 0
- **_on ** 私有静态方法,用于添加事件监听器 ,接受事件类型、事件名称和回调函数作为参数
- on 静态方法,用于添加普通类型的事件监听器
- once 静态方法,用于添加只触发一次的事件监听器
- emit 静态方法,用于触发指定类型的事件,会遍历该事件类型对应的所有回调函数并执行它们
- off 静态方法,用于移除指定事件 ID 的事件监听器,接受事件 ID 作为必选参数,可选地接受一个回调函数作为参数,如果只传入事件 ID,将移除该 ID 对应的整个事件项;如果同时传入回调函数,将只移除该事件项中对应的回调函数
class MyEmitter {
// 存储所有事件监听器的私有静态数组,初始为空
private static listeners: IEventItem[] = [];
// 用于生成唯一事件ID的私有静态变量,初始值为0
private static _eventId: number = 0;
// 私有静态属性的getter方法,每次调用返回递增后的_eventId值
// 用于获取下一个可用的事件ID
private static get eventId() {
}
// 私有静态方法,用于添加事件监听器
// 接受事件类型、事件名称和回调函数作为参数
private static _on(eventType: eventType, type: string, cb: Function) {
}
// 静态方法,用于添加普通类型的事件监听器
// 接受事件名称和回调函数作为参数
// 内部调用私有静态方法 _on 并传入 "normal" 事件类型
static on(type: string, cb: Function) {
}
// 静态方法,用于添加只触发一次的事件监听器
// 接受事件名称和回调函数作为参数
// 内部调用私有静态方法 _on 并传入 "once" 事件类型
static once(type: string, cb: Function) {
}
// 静态方法,用于触发指定类型的事件
// 接受事件名称作为必选参数,可选地接受一个数据参数
// 会遍历该事件类型对应的所有回调函数并执行它们
static emit<T = undefined>(type: string, data?: T) {
}
// 静态方法,用于移除指定事件ID的事件监听器
// 接受事件ID作为必选参数,可选地接受一个回调函数作为参数
// 如果只传入事件ID,将移除该ID对应的整个事件项;如果同时传入回调函数,将只移除该事件项中对应的回调函数
static off(eventId: number, cb?: Function) {
}
调用示例
@Entry
@Component
struct Index {
tid: number = -1
build() {
Column({ space: 10 }) {
Button("1 注册常规事件")
.onClick(() => {
this.tid = MyEmitter.on("login", (res: object) => {
console.log(JSON.stringify(res))
})
})
Button("1 取消常规事件")
.onClick(() => {
MyEmitter.off(this.tid)
})
Button("1 触发常规事件")
.onClick(() => {
MyEmitter.emit("login", 100)
})
Button("2 注册一次性事件")
.onClick(() => {
this.tid = MyEmitter.once("login2", (res: object) => {
console.log(JSON.stringify(res))
})
})
Button("2 取消一次性事件")
.onClick(() => {
MyEmitter.off(this.tid)
})
Button("2 触发一次性事件")
.onClick(() => {
MyEmitter.emit("login2", 100)
})
Button("3 注册具名事件")
.onClick(() => {
this.tid = MyEmitter.on("login1", this.fn1)
})
Button("3 取消具名事件")
.onClick(() => {
MyEmitter.off(this.tid, this.fn1)
})
Button("3 触发具名事件")
.onClick(() => {
MyEmitter.emit("login1", 300)
})
}
.height('100%')
.width('100%')
}
fn1(n: number) {
console.log("具名事件", n)
}
}
效果图
总结
发布 - 订阅模式是一种非常有用的软件设计模式,它可以实现系统的解耦、可扩展性和灵活性。在实际应用中,需要根据具体的需求和场
景选择合适的实现方式