Observer Pattern

This code is awful. You have to know obserber’s detail and call update method one by one. What if observers increase or decrease? You have to maintain them. This is a nightmare.

fun main(args: Array<String>) {
    val someClass1 = SomeClass1()
    val someClass2 = SomeClass2()
    val someClass3 = SomeClass3()

    someClass1.updateSomeClass1() // SomeClass 1 is updated!
    someClass2.updateSomeClass2() // SomeClass 2 is updated!
    someClass3.updateSomeClass3() // SomeClass 3 is updated!
}

class SomeClass1 {
    fun updateSomeClass1() = println("SomeClass 1 is updated!")
}

class SomeClass2 {
    fun updateSomeClass2() = println("SomeClass 2 is updated!")
}

class SomeClass3 {
    fun updateSomeClass3() = println("SomeClass 3 is updated!")
}

With Observer Pattern, you do not have to know observer’s detail. All you have to know is that observers have same interface.

You can attach the observers to subject like below. Once you attached it, subject can notify observers to update without knowing its detail.

fun main(args: Array<String>) {
    val subject = Subject()

    val observer1 = Observer1().also {
        subject.attach(it)
    }

    val observer2 = Observer2().also {
        subject.attach(it)
    }

    val observer3 = Observer3().also {
        subject.attach(it)
    }

    subject.notificate()
    // Observer 1 is updated!
    // Observer 2 is updated!
    // Observer 3 is updated!
}

If you’d like to stop updating a observer, you can detach it.

    subject.detach(observer3)

    subject.notificate()
    // Observer 1 is updated!
    // Observer 2 is updated!

Subject have a collection of observers that have same interface. You can add or remove the observer from collection. Also, you can update observers using a loop.

class Subject {
    private val observers = mutableListOf<Observer>()

    fun attach(observer: Observer) = observers.add(observer)

    fun detach(observer: Observer) = observers.remove(observer)

    fun notificate() = observers.forEach { observer ->
        observer.update()
    }
}

interface Observer {
    fun update()
}

Observer have the same interface, so subject can updated through the interface withou knowing the detail of observers. On the other hand, observers do not know anything about the subject.

class Observer1: Observer {
    override fun update() = println("Observer 1 is updated!")
}

class Observer2: Observer {
    override fun update() = println("Observer 2 is updated!")
}

class Observer3: Observer {
    override fun update() = println("Observer 3 is updated!")
}