ArkUl设计模式之订阅模式 原创
ArkUl的 Emitter 对象具有持续订阅事件和单次订阅事件、取消订阅事件、触发事件的能力。我们可以将它做为封装的参考,来自己实现一个类似的封装。
一、什么是订阅模式
发布-订阅模式是一种软件架构设计模式,属于行为型设计模式,用于解耦生产者(发布者)和消费者(订阅者)之间的关系。在这种模式中,发布者负责发布消息,而订阅者则可以选择订阅他们感兴趣的消息类型。当有新消息发布时,订阅者将收到通知并执行相应的操作。
优点:
(1)解耦性 :发布-订阅模式实现了生产者和消费者之间的解耦,发布者和订阅者之间的通信通过中介(例如消息队列、事件总线)进行,彼此不直接依赖或知晓对方的存在,从而提高了系统的灵活性和可维护性。
(2)异步通信: 由于发布者和订阅者之间的通信通常是通过消息队列或事件总线进行的,因此支持异步通信。这使得系统能够更高效地处理大量消息,并提高了响应性。
(3)扩展性:由于发布者和订阅者之间的解耦,系统可以更容易地扩展。新的发布者或订阅者可以被添加而不影响现有的组件。
(4)灵活性: 发布-订阅模式允许任意数量的发布者和订阅者存在,并且支持多对多的通信。发布者和订阅者可以根据需求动态地添加、删除或修改,而不影响整个系统的运行。
二、事件订阅类型InnerEvent
InnerEvent为订阅或发送的事件,eventId为事件ID,由开发者定义用来辨别事件。priority为事件被投递的优先级。
IMMEDIATE:表示事件被立即投递。
HIGH:表示事件先于LOW优先级投递。
LOW:表示事件优于IDLE优先级投递,事件的默认优先级是LOW。
IDLE:表示在没有其他事件的情况下,才投递该事件
注意:订阅事件时EventPriority不生效。也就是说在emitter.on(event)订阅某事件时,设置priority的优先级是不生效的。
三、封装Emitter工具类
import { emitter } from "@kit.BasicServicesKit";
export class EmitterUtil {
/**
* 持续订阅指定事件,并在接收到该事件时,执行对应的回调
*/
static on(eventId: number, callBack: (eventData: emitter.EventData) => void) {
let event: emitter.InnerEvent = {
eventId: eventId, //事件id
}
//订阅事件event
emitter.on(event, callBack)
}
/**
* 通过传入事件id,取消订阅对应的事件
* @param eventId
*/
static off(eventId: number) {
emitter.off(eventId)
}
/**
* 发布事件
*/
static emit(eventId: number, data?: emitter.EventData) {
let event: emitter.InnerEvent = {
eventId: eventId, //事件id
priority: emitter.EventPriority.IMMEDIATE//事件立即被投递
}
let eventData: emitter.EventData = {
data: data
}
emitter.emit(event, eventData)
}
/**
* 单次订阅事件
* @param eventId
* @param callBack
*/
static once(eventId: number, callBack: (eventData: emitter.EventData) => void){
let event: emitter.InnerEvent = {
eventId: eventId, //事件id
}
//订阅事件event
emitter.once(event,callBack)
}
}
四、调用示例
Emitter在同一进程同一线程下的通信
import { EmitterUtil } from '../EmitterUtil'
import emitter from '@ohos.events.emitter'
import { EmitterCode } from '../EmitterCode'
@Component
@Entry
struct Index {
aboutToAppear(): void {
//订阅一个接收用户信息的事件
EmitterUtil.on(EmitterCode.USER_INFO, (data: emitter.EventData) => {
})
}
aboutToDisappear(): void {
//取消订阅事件
EmitterUtil.off(EmitterCode.USER_INFO)
}
build() {
Column() {
Button("发送事件").onClick(() => {
//发布用户Tom信息的事件
EmitterUtil.emit(EmitterCode.USER_INFO, {
data: {
name: "Tom",
age: 20
}
})
})
}.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
五、Emitter在同一进程不同线程下的通信
import { EmitterUtil } from '../EmitterUtil'
import emitter from '@ohos.events.emitter'
import { EmitterCode } from '../EmitterCode'
import { promptAction } from '@kit.ArkUI'
import { JSON, taskpool } from '@kit.ArkTS'
@Concurrent
function add(num1: number, num2: number): number {
// 子线程中发送事件
EmitterUtil.emit(EmitterCode.USER_INFO,{
data: {
name: "Tom",
age: 20
}
})
return num1 + num2;
}
@Component
@Entry
struct Index {
aboutToAppear(): void {
//订阅一个接收用户信息的事件
EmitterUtil.on(EmitterCode.USER_INFO, (data: emitter.EventData) => {
promptAction.showToast({message:JSON.stringify(data.data)})
})
}
aboutToDisappear(): void {
//取消订阅事件
EmitterUtil.off(EmitterCode.USER_INFO)
}
build() {
Column() {
Button("发送事件").onClick(() => {
let task: taskpool.Task = new taskpool.Task(add, 1, 2)
taskpool.execute(task)
})
}.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}