The Observer Pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
It's a very useful pattern for implementing event-driven systems, and it's also one of the behavioral design patterns.
The Observer Pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
It's a very useful pattern for implementing event-driven systems, and it's also one of the behavioral design patterns.
The Observer Pattern has the following participants:
The Observer Pattern is used in the following situations:
Kotlin doesn't have a built-in Observer Pattern, but it's easy to implement it.
First, let's create the Subject interface:
interface Subject {
fun addObserver(observer: Observer)
fun removeObserver(observer: Observer)
fun notifyObservers()
}
As you can see, the Subject interface has three methods:
Now let's create the Observer interface:
interface Observer {
fun update(subject: Subject)
}
The Observer interface has only one method:
Let's now create a ConcreteSubject class that implements the Subject interface:
class ConcreteSubject : Subject {
private val observers = mutableListOf<Observer>()
private var state: Int = 0
override fun addObserver(observer: Observer) {
observers.add(observer)
}
override fun removeObserver(observer: Observer) {
observers.remove(observer)
}
override fun notifyObservers() {
for (observer in observers) {
observer.update(this)
}
}
fun setState(state: Int) {
this.state = state
notifyObservers()
}
fun getState(): Int {
return state
}
}
As you can see, the ConcreteSubject class maintains a list of observers and notifies them when the subject's state changes.
Finally, let's create a ConcreteObserver class that implements the Observer interface:
class ConcreteObserver : Observer {
private var state: Int = 0
override fun update(subject: Subject) {
state = subject.getState()
}
fun getState(): Int {
return state
}
}
The ConcreteObserver class simply stores the state of the subject and provides a getter method to access it.
Let's now write a test to see the Observer Pattern in action:
import org.junit.Test
import kotlin.test.assertEquals
class ObserverPatternTest {
@Test
fun testObserverPattern() {
val subject = ConcreteSubject()
val observer1 = ConcreteObserver()
val observer2 = ConcreteObserver()
subject.addObserver(observer1)
subject.addObserver(observer2)
subject.setState(1)
assertEquals(1, observer1.getState())
assertEquals(1, observer2.getState())
subject.setState(2)
assertEquals(2, observer1.getState())
assertEquals(2, observer2.getState())
subject.removeObserver(observer1)
subject.setState(3)
assertEquals(2, observer1.getState())
assertEquals(3, observer2.getState())
}
}
In this test, we first create a ConcreteSubject and two ConcreteObservers. We then add the observers to the subject and change the subject's state. We assert that the observers' states have changed accordingly. Finally, we remove one of the observers and change the subject's state again. We assert that only the remaining observer's state has changed.