Behavioural Design patterns: Observer
Observer is one of the most popular design patterns. It has been used a lot on many software use cases and thus many languages out there provide it as a part of their standard library.
By using the observer pattern we can tackle the following challenges.
- Dependency with objects defined in a way that avoids tight coupling
- Changes on an object changes its dependent objects
- An object can notify all of its dependent objects
Imagine the scenario of a device with multiple sensors. Some parts of the code will need to get notified when new sensor data arrive and thus act accordingly. We will start by a simple class which represents the json data.
package com.gkatzioura.design.behavioural.observer; public class SensorData { private final String sensor; private final Double measure; public SensorData(String sensor, Double measure) { this.sensor = sensor; this.measure = measure; } public String getSensor() { return sensor; } public Double getMeasure() { return measure; } }
The we shall create the observer interface. Every class that implements the observer interface shall be notified once a new object is created.
package com.gkatzioura.design.behavioural.observer; public interface Observer { void update(SensorData sensorData); }
Next step is to create the observable interface. The observable interface will have methods in order to register the observers that need to get notified.
package com.gkatzioura.design.behavioural.observer; public interface Observable { void register(Observer observer); void unregister(Observer observer); void updateObservers(); }
Now let us put some implementations.
The sensor listener will receive data from the sensors and notify the observers about the presence of data.
package com.gkatzioura.design.behavioural.observer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class SensorReceiver implements Observable { private List data = new ArrayList(); private List observers = new ArrayList(); @Override public void register(Observer observer) { observers.add(observer); } @Override public void unregister(Observer observer) { observers.remove(observer); } public void addData(SensorData sensorData) { data.add(sensorData); } @Override public void updateObservers() { /** * The sensor receiver has retrieved some sensor data and thus it will notify the observer * on the data it accumulated. */ Iterator iterator = data.iterator(); while (iterator.hasNext()) { SensorData sensorData = iterator.next(); for(Observer observer:observers) { observer.update(sensorData); } iterator.remove(); } } }
The we will create an observer which shall log the sensor data received to database, it might be an influxdb or an elastic search you name it.
package com.gkatzioura.design.behavioural.observer; public class SensorLogger implements Observer { @Override public void update(SensorData sensorData) { /** * Persist data to the database */ System.out.println(String.format("Received sensor data %s: %f",sensorData.getSensor(),sensorData.getMeasure())); } }
Let’s put the all together.
package com.gkatzioura.design.behavioural.observer; public class SensorMain { public static void main(String[] args) { SensorReceiver sensorReceiver = new SensorReceiver(); SensorLogger sensorLogger = new SensorLogger(); sensorReceiver.register(sensorLogger); sensorReceiver.addData(new SensorData("temperature",1.2d)); sensorReceiver.updateObservers(); } }
You can find the source code on github.
Published on Java Code Geeks with permission by Emmanouil Gkatziouras, partner at our JCG program. See the original article here: Behavioural Design patterns: Observer Opinions expressed by Java Code Geeks contributors are their own. |