Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何在 Java 中實現「事件驅動架構」 #2

Open
jingkecn opened this issue Sep 16, 2018 · 0 comments
Open

如何在 Java 中實現「事件驅動架構」 #2

jingkecn opened this issue Sep 16, 2018 · 0 comments
Assignees
Labels
design pattern Design pattern related stuff dev Development related stuff Java Java related stuff

Comments

@jingkecn
Copy link
Owner

jingkecn commented Sep 16, 2018

背景

在軟件開發中,「事件驅動架構(簡稱 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 中 delegateevent 相對應的又是什麼呢?
綜上可知,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.
@jingkecn jingkecn changed the title 論 Android 中的事件驅動架構 論 Java 中的事件驅動架構 Sep 16, 2018
@jingkecn jingkecn added dev Development related stuff design pattern Design pattern related stuff labels Sep 16, 2018
@jingkecn jingkecn changed the title 論 Java 中的事件驅動架構 如何在 Java 中實現「事件驅動架構」 Sep 16, 2018
@jingkecn jingkecn self-assigned this Sep 16, 2018
@jingkecn jingkecn added the Java Java related stuff label Sep 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design pattern Design pattern related stuff dev Development related stuff Java Java related stuff
Projects
None yet
Development

No branches or pull requests

1 participant