I just learnt my first design from The Head First Design Pattern book. Today, I learnt about the Observer pattern.
According to Head First Design Patterns, the Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependent are notified and updated automatically. The object that sends out changes is called the Subject while objects that receive changes are called the Observers.
I also got to the Observer pattern is slightly different from the Publish-Subcribe pattern. In the Observer pattern, there is no middle filtering out the events sent to the observers by the subject. Event are sent directly to observers. This is not the case in the Publish-Subscribe pattern. In the Publish-Subscribe pattern, the event sent by the Publisher(subject) first goes to an Event-bus. The Event-bus then filters and sends the events to subcribers(observers) accordingly.
For example,in order to implement the Observer pattern, you need two interfaces: Subject and Observer.
interface Subject {
fun registerObserver(o : Observer)
fun removeObserver(o: Observer)
fun notifyObservers()
}
The Subject
interface defines the behaviour for subjects. Subjects can register an observer, remove an observer and notify observers of changes in its state.
interface Observer {
fun update(title: String, airTime: String)
}
The Object
interface defines the behaviour for objects. Object can receive new update of anime with their airing time.
class AnimeSubject : Subject {
private val observers = mutableListOf<Observer>()
private var title: String = ""
private var airTime: String = ""
override fun registerObserver(o: Observer) {
observers.add(o)
}
override fun removeObserver(o: Observer) {
observers.remove(o)
}
override fun notifyObservers() {
observers.forEach { observer: Observer ->
observer.update(title, airTime)
}
}
fun setAnime(title: String, airTime: String) {
this.title = title
this.airTime = airTime
notifyObservers()
}
}
The AnimeSubject
implements the Subject
interface. It contains a list of observer. Whenever the AnimeSubject
state changes, it notifies its observer of the changes.
class SanmiObserver(val animeSubject: AnimeSubject) : Observer {
init {
animeSubject.registerObserver(this)
}
override fun update(title: String, airTime: String) {
println("Thanks for notifying me about $title airing at $airTime")
}
}
The SanmiObserver
implements the Observer
interface. It also takes an AnimeSubject
as a dependency. Registering itself as an observer of AnimeSubject
class AdeObserver(val animeSubject: AnimeSubject) : Observer {
init {
animeSubject.registerObserver(this)
}
override fun update(title: String, airTime: String) {
println("Yo for notifying me about $title airing at $airTime")
}
}
fun main() {
val animeSubject = AnimeSubject()
val sanmiObserver = SanmiObserver(animeSubject)
val adeObserver = AdeObserver(animeSubject)
animeSubject.setAnime("Tokyo Revenger", "21:30")
}
prints:
Thanks for notifying me about Tokyo Revenger airing at 21:30
Yo for notifying me about Tokyo Revenger airing at 21:30
Whenever the animeSubject
changes its state, its observer will be notified of the changes.
The advantages of using the Observer pattern are
- Subjects and observers are loosely coupled so changes in either the subject or observer will not affect each other.This also makes it very easy to define new observers, add and remove observer at any time.
- It makes communication between different parts of your software easier.
- It also reduces the amount of resources used as you don't have to be pulling for the existence of new information every time because whenever the state of your subject changes, your observers will be notified.
Common use case for the Observer pattern in Android development for example would be, setting onClickListerner, registering for changes of any kind, communication between recyclerviews and fragments/activities.
Top comments (0)