Delphi 中基于接口的事件总线实现
在现代应用程序开发中,组件间的松耦合通信至关重要。事件总线(Event Bus)是一种设计模式,它允许对象之间通过发布和订阅机制进行通信,而无需彼此直接引用。这种模式特别适用于跨模块、跨层级或跨平台的应用场景。
Delphi 社区提供了一个功能强大的开源事件总线库:delphi-event-bus,目前版本已迭代至 2.0。该版本完全基于接口实现,结构更清晰,使用更灵活,并支持 Windows、macOS、Linux 甚至移动平台。
定义事件接口
使用此框架的第一步是定义一个用于传递数据的接口。例如,我们希望在文本内容变更时通知其他窗体,可以声明如下接口:
type
ITextUpdateEvent = interface
['{A5D3F1C8-7E2B-4A6F-B6F3-12C9E85D0ABC}']
function GetContent: string;
procedure SetContent(const Value: string);
property Content: string read GetContent write SetContent;
end;
实现事件类
接下来创建一个类来实现该接口。由于事件总线依赖接口生命周期管理,推荐从 TInterfacedObject 继承:
type
TTextUpdateEvent = class(TInterfacedObject, ITextUpdateEvent)
private
FContent: string;
function GetContent: string;
procedure SetContent(const Value: string);
public
property Content: string read GetContent write SetContent;
end;
function TTextUpdateEvent.GetContent: string;
begin
Result := FContent;
end;
procedure TTextUpdateEvent.SetContent(const Value: string);
begin
FContent := Value;
end;
封装事件实例创建
为了便于复用,可编写一个辅助函数来生成事件对象:
function CreateTextUpdateEvent(const AText: string): ITextUpdateEvent;
begin
Result := TTextUpdateEvent.Create;
Result.Content := AText;
end;
发布事件
当某个操作触发时(如编辑框内容变化),可通过全局事件总线发布消息。假设有一个主窗体中的 Memo1,其内容改变后需广播:
procedure TMainForm.Memo1Change(Sender: TObject);
var
Event: ITextUpdateEvent;
begin
Event := CreateTextUpdateEvent(Memo1.Text);
GlobalEventBus.Post(Event);
end;
订阅并处理事件
接收方需要定义一个带有 [Subscribe] 特性的方法,参数类型必须与发布的接口一致:
type
TObserverForm = class(TForm)
MemoObserver: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
[Subscribe]
procedure HandleTextUpdate(AEvent: ITextUpdateEvent);
end;
procedure TObserverForm.HandleTextUpdate(AEvent: ITextUpdateEvent);
begin
MemoObserver.Lines.Text := AEvent.Content;
end;
注册订阅者
只有注册后的对象才能接收到事件。通常在窗体创建和销毁时进行注册与注销:
procedure TObserverForm.FormCreate(Sender: TObject);
begin
GlobalEventBus.RegisterSubscriberForEvents(Self);
end;
procedure TObserverForm.FormDestroy(Sender: TObject);
begin
GlobalEventBus.UnregisterForEvents(Self);
end;
至此,一个完整的发布-订阅流程已经建立。主窗体修改内容后,观察窗体会自动更新显示,两者无任何直接依赖,实现了高度解耦。
项目自带示例程序 VCLMessaging.dpr 演示了上述机制的实际应用,建议下载源码运行体验。