Project Technical Lead
Java design pattern: Observer
Today we will look at another Java design pattern from the category of behavioral patterns – Observer. Design patterns in this category deal with the communication (interaction) between objects and their responsibility.
What is the Observer design pattern?
Observer is a design pattern that allows us to define a mechanism for taking messages and notifying all interested objects of any events that occur on the observed object.
What problem does the Observer design pattern solve?
The Observer pattern is a design pattern that solves the problem of tracking a change in the state of an object so that all of its dependent objects (observers) are automatically notified and updated when a change occurs in the object. This pattern allows to establish weak ties between the subject (the object that changes its state) and the observers (the objects that want to be informed about the change).
The Observed Object –Publisher goes through events of interest to other objects. These events occur when it changes its state or performs an action. Publishers include a subscription infrastructure that allows newSubscribers to join and existing Subscribers to leave the list.
When a new event occurs, the publisher traverses the subscription list and calls the notification method declared in the subscriber interface on each subscriber object. The subscriber interface in most cases consists of a single update method.
The method can have several parameters that allow the publisher to report more detailed information about the event along with the update. Specific subscribers take their own actions in response to notices issued by the publisher.
All these classes must implement the same interface, so the publisher is not directly linked to specific classes. Subscribers usually need contextual information to process the update correctly. The client creates publisher and subscriber objects separately and then registers subscribers for publisher updates.
Example of Observer implementation in Java
To demonstrate a practical application of the Observer design pattern, we create a simple simulation of a YouTube channel where users (subscribers) can subscribe to receive notifications about new videos on that channel or unsubscribe.
IOdoberatel.java
package designpatterns;
public interface IOdoberatel {
void aktualizovat(String sprava);
}
The IOdoberatel interface defines the update method that specific subscribers will implement. It is used to update in case of new content.
YouTubeUser.java
package designpatterns;
public class YouTubePouzivatel implements IOdoberatel {
private String meno;
public YouTubePouzivatel(String meno) {
this.meno = meno;
}
@Override
public void aktualizovat(String videoTitul) {
System.out.println(meno + " dostal/a notifikáciu o novom videu: " + videoTi-tul);
}
@Override
public String toString() {
return meno;
}
}
Trieda YouTubePouzivatel reprezentuje konkrétneho používateľa, ktorý môže prijímať notifikácie o nových videách.
IYoutubeKanal.java
package designpatterns;
public interface IYoutubeKanal {
void odoberat(IOdoberatel odoberatel);
void zrusitOdber(IOdoberatel odoberatel);
void upozornitOdoberatelov(String videoTitul);
}
The IYoutubeChannel interface defines the subscribe, zrusitOdber, and upozornitOdoberatelov methods that a particular YouTube channel will implement. It is used to manage subscribers.
YouTubeKanal.java
package designpatterns;
import java.util.ArrayList;
import java.util.List;
public class YouTubeKanal implements IYoutubeKanal {
private List<IOdoberatel> odoberatelia = new ArrayList<>();
private String nazovKanala;
public YouTubeKanal(String nazovKanala) {
this.nazovKanala = nazovKanala;
}
@Override
public void odoberat(IOdoberatel odoberatel) {
odoberatelia.add(odoberatel);
System.out.println(odoberatel + " odoberá " + nazovKanala);
}
@Override
public void zrusitOdber(IOdoberatel odoberatel) {
odoberatelia.remove(odoberatel);
System.out.println(odoberatel + " odhlásil/a odber " + nazovKanala);
}
@Override
public void upozornitOdoberatelov(String videoTitul) {
for(IOdoberatel odoberatel : odoberatelia) {
odoberatel.aktualizovat(videoTitul);
}
}
public void nahratNoveVideo(String videoTitul) {
System.out.println("Nové video bolo pridané: " + videoTitul);
upozornitOdoberatelov(videoTitul);
}
}
The YouTubeKanalclass represents a specific YouTube channel that can subscribe and unsubscribe subscribers and notify them of new videos.
Main.java
import designpatterns.IOdoberatel;
import designpatterns.IYoutubeKanal;
import designpatterns.YouTubeKanal;
import designpatterns.YouTubePouzivatel;
public class Main {
public static void main(String[] args) {
// Vytvorenie YouTube kanalu
YouTubeKanal youtubeKanal = new YouTubeKanal("[Programovanie v Jave]");
// Vytvorenie odoberatelov (subscribers)
IOdoberatel odoberatel1 = new YouTubePouzivatel("Subscriber1");
IOdoberatel odoberatel2 = new YouTubePouzivatel("Subscriber2");
// Nastavenie odberov YouTube kanala
youtubeKanal.odoberat(odoberatel1);
youtubeKanal.odoberat(odoberatel2);
// Pridanie noveho videa, vsetci odoberatelia dostanu upozornenie
youtubeKanal.nahratNoveVideo("Navrhove vzory v Jave");
// Odoberatel 1 odhlasi odber
youtubeKanal.zrusitOdber(odoberatel1);
// Pridanie dalsieho videa, notifikaciu dostatne len Odoberatel 2
youtubeKanal.nahratNoveVideo("Java SDK 21");
}
}
In the Main class, we simulate the operation of a single YouTube channel where users (subscribers) can subscribe and when a new video is added, all subscribers are notified. Also see that after unsubscribing, the user stops receiving notifications of new content.
The output of this example is:
Summary
The Observer pattern is used in systems that process events, e.g. in GUI components (mouse click on a button), but they are useful wherever we want to react flexibly to a change on the observed object.
We have prepared the files with the above example in the form of code that you can run directly in Java. Download the Java Observer code here.
If you’re looking for a job and you’re a Java developer, check out our employee benefits and respond to our job offers.