172. Implementing the Observer pattern

In a nutshell, the Observer pattern relies on an object (known as the subject) that automatically notifies its subscribers (known as observers) when certain events happen.

For example, the fire station headquarters can be the subject, and the local fire stations can be the observers. When a fire has started, the fire station headquarters notifies all local fire stations and sends them the address where the fire is taking place. Each observer analyzes the received address and, depending on different criteria,  decides whether to extinguish the fire or not.

All the local fire stations are grouped via an interface called FireObserver. This method defines a single abstract method that is invoked by the fire station headquarters (subject):

public interface FireObserver {
void fire(String address);
}

Each local fire station (observer) implements this interface and decides whether to extinguish the fire or not in the fire() implementation. Here, we have three local stations (Brookhaven, Vinings, and Decatur):

public class BrookhavenFireStation implements FireObserver {

@Override
public void fire(String address) {
if (address.contains("Brookhaven")) {
System.out.println(
"Brookhaven fire station will go to this fire");
}
}
}

public class ViningsFireStation implements FireObserver {
// same code as above for ViningsFireStation
}

public class DecaturFireStation implements FireObserver {
// same code as above for DecaturFireStation
}

Half of the job is done! Now, we need to register these observers to be notified by the subject. In other words, each local fire station needs to be registered as an observer to the fire station headquarters (subject). For this, we declare another interface that defines the subject contract for registering and notifying its observers:

public interface FireStationRegister {
void registerFireStation(FireObserver fo);
void notifyFireStations(String address);
}

Finally, we can write the fire station headquarters (subject):

public class FireStation implements FireStationRegister {

private final List<FireObserver> fireObservers = new ArrayList<>();

@Override
public void registerFireStation(FireObserver fo) {
if (fo != null) {
fireObservers.add(fo);
}
}

@Override
public void notifyFireStations(String address) {
if (address != null) {
for (FireObserver fireObserver: fireObservers) {
fireObserver.fire(address);
}
}
}
}

Now, let's register our three local stations (observers) to the fire station headquarters (subject):

FireStation fireStation = new FireStation();
fireStation.registerFireStation(new BrookhavenFireStation());
fireStation.registerFireStation(new DecaturFireStation());
fireStation.registerFireStation(new ViningsFireStation());

Now, when a fire occurs, the fire station headquarters will notify all registered local fire stations:

fireStation.notifyFireStations(
"Fire alert: WestHaven At Vinings 5901 Suffex Green Ln Atlanta");

The Observer pattern was successfully implemented there.

This is another classical case of boilerplate code. Each local fire station needs a new class and implementation of the fire() method.

However, lambdas can help us again! Check out the FireObserver interface. It has a single abstract method; therefore, this is a functional interface:

@FunctionalInterface
public interface FireObserver {
void fire(String address);
}

This functional interface is an argument of the Fire.registerFireStation() method. In this context, we can pass a lambda to this method instead of a new instance of a local fire station. The lambda will contain the behavior in its body; therefore, we can delete the local station classes and rely on lambdas, as follows:

fireStation.registerFireStation((String address) -> {
if (address.contains("Brookhaven")) {
System.out.println(
"Brookhaven fire station will go to this fire");
}
});

fireStation.registerFireStation((String address) -> {
if (address.contains("Vinings")) {
System.out.println("Vinings fire station will go to this fire");
}
});

fireStation.registerFireStation((String address) -> {
if (address.contains("Decatur")) {
System.out.println("Decatur fire station will go to this fire");
}
});

Done! No more boilerplate code.

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

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