Chapter 22. Events Between Java Components

A.Mahdy AbdelAziz

One of the core concepts of object orientation in Java is that every class can be considered to be a component. Components can be extended or included to form bigger components. The final application is also considered a component. Components are like Lego blocks that build up a bigger structure.

An event in Java is an action that changes the state of a component. For example, if your component is a button, then clicking on that button is an event that changes the state of the button to be clicked.

Events do not necessarily happen only on visual components. For example, you can have an event on a USB component that a device is connected. Or an event on a network component that data is transferred. Events help to decouple the dependencies between components. 

Assume we have an Oven component and a Person component. These two components exist in parallel and work independently of one another. We should not make Person part of Oven, nor the other way around. To build a smart house, we want the Oven to prepare food once Person is hungry. Here are two possible implementations:

  1. Oven checks Person in fixed, short intervals. This annoys Person and is also expensive for Oven if we want it to check on multiple instances of Person.

  2. Person comes with a public event, Hungry, to which Oven is subscribed. Once Hungry is fired, Oven is notified and starts preparing food.

The second solution uses the event architecture to handle the listening and communication between components efficiently and without a direct coupling between Person and Oven, because Person will fire the event, and any component, such as Oven, Fridge, and Table, can listen to that event without any special handling from the Person component.

Implementing events for a Java component can take different forms, depending on how they are expected to be handled. To implement a minimal HungerListener in the Person component, first, create a listener interface:

@FunctionalInterface
public interface HungerListener {
   void hungry();
}

Then, in the Person class, define a list to store the listeners:

private List<HungerListener> listeners = new ArrayList<>();

Define an API to insert a new listener:

public void addHungerListener(HungerListener listener) {
   listeners.add(listener);
}

You can create a similar API for removing a listener. Also, add a method to trigger the action of being hungry to notify all listeners of the event:

public void becomesHungry() {
   for (HungerListener listener : listeners)
       listener.hungry();
}

Finally, from the Oven class, add code that listens to the event and implements the action when the event is fired:

Person person = new Person();
person.addHungerListener(() -> {
   System.err.println("The person is hungry!");
   // Oven takes action here
});

And to try it out:

person.becomesHungry();

For fully decoupled code, the last section should be in an independent class that has an instance of Person and Oven, and handles the logic between them. Similarly, we can add other actions for Fridge, Table, and so on. They all will get notified only once the Person becomesHungry.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset