如何在 Java 中實現「事件驅動架構」
jingkecn opened this issue · 0 comments
背景
在軟件開發中,「事件驅動架構(簡稱 EDA,下同)」是實現松耦合系統設計的其中一種模式。
源於 .Net 的靈感
在 .Net 中,「委託(Delegation)」是實現 EDA 的基本模式,其「事件(Event)」通過 delegate
關鍵字和 event
關鍵字 聲明定義:
// A delegate is a type that represents references to methods
// with a particular parameter list and return type.
delegate void SampleEventHandler(/* params */);
// The event keyword is used to declare an event in a publisher class.
event SampleEventHandler SampleEvent;
而「事件」則由「事件監聽目標(Event Target)」觸發(Dispatch),并由「事件監聽器(Event Listener)」監聽(Listen)。
事件監聽目標(Event Target)
一個「事件監聽目標」通常負責:
- 定義事件(Event Definition)
- 觸發事件(Event Dispatching)
/**
* A sample of event target in C#.
**/
class SampleEventTarget {
// Event definition.
delegate void SampleEventHandler(/* params */);
event SampleEventHandler SampleEvent;
// Event dispatching.
// Dispatch SampleEvent somewhere in member methods.
// SampleEvent?.invoke(/* params */);
}
事件監聽器(Event Listener)
一個「事件監聽器」則負責在監聽到事件時處理(Handle)事件。
/**
* A sample of event listener in C#.
**/
class SampleEventListener {
void OnSampleEventInvoked(/* params */) {
// Handle event here.
}
}
註冊(Registration)和註銷(Cancellation)
通常來說,在全局作用域,中控負責:
- 向事件目標「註冊」事件監聽器
- 向事件目標「註銷」事件監聽器
var sampleEventTarget = new SampleEventTarget();
var sampleEventListener = new SampleEventListener();
del lambdaEventHandler = (/* params */) => {
sampleEventListener.OnSampleEventInvoked(/* params */);
};
// Register lambda event handler to event target.
sampleEventTarget.SampleEvent += lambdaEventHandler;
// Cancel lambda event handler from event target.
sampleEventTarget.SampleEvent -= lambdaEventHandler;
// Register event handler reference to event target.
sampleEventTarget.SampleEvent += sampleEventListener.OnSampleEventInvoked;
// Cancel event handler reference from event target.
sampleEventTarget.SampleEvent -= sampleEventListener.OnSampleEventInvoked;
在 Java 中實現
那麼在 Java 中,與 .Net 中 delegate
和 event
相對應的又是什麼呢?
綜上可知,delegate
聲明定義了事件處理方法的函數簽名,那麼這對應了 Java 中的函數式接口(Functional Interface):
// Defines an event handler.
@FunctionalInterface
interface ISampleEventHandler {
void invoke(/* params */);
}
那麼 event
呢?經觀察,我們可推定,.Net 中的 event
聲明了一個集合(由 +=
和 -=
操作符推測),而其元素為 SampleEventHandler
委託類型:
// An event in Java can be a collection of event handlers.
HashSet<ISampleEventHandler> sampleEvent = new HashSet();
那麼,接下來我們只需要依樣畫葫蘆就好了:
事件監聽目標(Event Target)
/**
* A sample of event target in Java.
**/
class SampleEventTarget {
// Defines an event handler.
@FunctionalInterface
interface ISampleEventHandler {
void invoke(/* params */);
}
// An event in Java can be a collection of event handlers.
HashSet<ISampleEventHandler> sampleEvent = new HashSet();
// Event dispatching.
// Dispatch sampleEvent somewhere in member methods.
// sampleEvent.forEach { handler -> handler.invoke(/* params */); };
}
事件監聽器(Event Listener)
/**
* A sample of event listener in Java.
**/
class SampleEventListener {
void onSampleEventInvoked(/* params */) {
// Handle event here.
}
}
註冊(Registration)和註銷(Cancellation)
SampleEventTarget sampleEventTarget = new SampleEventTarget();
SampleEventListener sampleEventListener = new SampleEventListener();
ISampleEventHandler sampleEventHandler = new ISampleEventHandler() {
@Override
void invoke(/* params */) {
sampleEventListener.onSampleEventInvoked(/* params */)
}
};
// Register event handler to event target.
sampleEventTarget.sampleEvent.add(sampleEventHandler);
// Cancel event handler from event target.
sampleEventTarget.sampleEvent.remove(sampleEventHandler);
Function</* param types */, Void> lambdaEventHandler = (/* params */) => {
sampleEventListener.onSampleEventInvoked(/* params */);
return null;
};
// Register lambda event handler to event target (Java 8+ required).
sampleEventTarget.sampleEvent.add(lambdaEventHandler);
// Cancel lambda event handler from event target.
sampleEventTarget.sampleEvent.remove(lambdaEventHandler);
// Register event handler reference to event target (Java 8+ required).
sampleEventTarget.SampleEvent.add(sampleEventListener::OnSampleEventInvoked);
// Cancel event handler reference from event target.
sampleEventTarget.SampleEvent.remove(sampleEventListener::OnSampleEventInvoked);
總結
本篇實現的思路中最反直覺的地方有兩處:
Lambda 表達式
Java 8 新增了 lambda 表達式以觸發現有的方法,因此上面 Java 中的
sampleEventTarget.sampleEvent.add((/* params */) -> { /* ... */ });
實際上是
sampleEventTarget.sampleEvent.add(new ISampleEventHandler() { /* ... */ });
的語法糖。
方法引用(Method References)
Java 8 中還新增了「方法引用(Method References)」,因此我們完全可以擺脫 ISampleEventHandler
實現的強制性,直接註冊與 ISampleEventHandler
有相同函數簽名的方法即可。
[!TODO]
Android 新增了 Kotlin 支持,在 Kotlin 中實現相同的「事件驅動架構」會更加接近 .Net 的模式。
參見
No. | Link |
---|---|
[1] | Wikipedia - Event-driven Architecture |
[2] | How to: Publish Events that Conform to .NET Framework Guidelines (C# Programming Guide). |
[3] | The Java™ Tutorials > Method References. |