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

How To: Implement Event-driven Architecture in Java #3

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

How To: Implement Event-driven Architecture in Java #3

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

Introduction

In computing systems, Event-driven Architecture (abbr. EDA,same in the following context) is
a pattern to implement a loosely coupled system.

Inspired by .Net

In .Net, Delegation is the basic pattern to implement EDA, and Event is declared and defined by delegate keyword and event keyword:

// 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;

However, an event is supposed to be dispatched by an event target and listened by an event listener.

Event Target

An event target is in charge of:

  • Definition of an event
  • Dispatching an event
/**
 * 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

An event listener is in charge of handling event if any invoked.

/**
 * A sample of event listener in C#.
 **/
class SampleEventListener {
    void OnSampleEventInvoked(/* params */) {
        // Handle event here.
    }
}

Registration and Cancellation

In general, a central controller in global scope is supposed to be in charge of:

  • Register an event listener to an event target.
  • Cancel an event listener from an event target.
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;

Implementation in Java

Then here comes the question: what can be things corresponding to delegate and event of .Net in Java?

From the observation on previous .Net samples, we can conclude that its delegate declares and defines a signature of the method handling event. Thus functional interface in Java is quite close to it.

// Defines an event handler.
@FunctionalInterface
interface ISampleEventHandler {
    void invoke(/* params */);
}

Then what can be corresponding to event?
Still from the observation on previous .Net samples, an object declared by keyword event has two operators: += and -=, it means that an event should be a collection. Then the elements of this collection should be defined by the delegate: SampleEventHandler

// An event in Java can be a collection of event handlers.
HashSet<ISampleEventHandler> sampleEvent = new HashSet();

Then all we have to do is to copy mechanically:

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 and 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);

Conclusion

The most counterintuitive part of implementations suggested by this post lies in:

Lambda Expressions

Lambda expressions were introduced as a new feature in Java 8 to invoke existing methods, so

sampleEventTarget.sampleEvent.add((/* params */) -> { /* ... */ });

is actually a syntax sugar of

sampleEventTarget.sampleEvent.add(new ISampleEventHandler() { /* ... */ });

Method References

Java 8 has also introduced Method References, so that we can get rid of the coerciveness of implementing the functional interface ISampleEventHandler, instead, we can register directly a method as an event handler as long as it has the same signature as defined in ISampleEventHandler.

[!TODO]
Android has recently supported Kotlin, EDA implementation in Kotlin should be much closer to .Net pattern and should also be much more comprehensive.

See Also

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 added dev Development related stuff design pattern Design pattern related stuff labels 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