Lesson 3
Observer Pattern in Kotlin
Observer Pattern

Welcome to the lesson on the Observer pattern! This pattern is a crucial part of Behavioral Design Patterns, focusing on establishing a one-to-many relationship between objects. When one object changes state, all its dependents are notified and updated automatically. It's a common pattern used in scenarios where an object needs to broadcast changes to multiple other objects.

What You Will Learn

In this lesson, you will:

  • Understand the basics of the Observer pattern.
  • Learn how to implement this pattern in Kotlin.
  • Recognize the significance of the Observer pattern in real-world applications.
Implementing the Observer Pattern

The Observer pattern consists of two key components: the Subject and the Observer. The Subject holds the state and notifies observers about any changes. The Observers receive updates whenever the Subject's state changes. This pattern is useful for broadcasting updates to multiple objects while maintaining decoupling since the Subject only knows the observers implement a specific interface.

In this lesson, we’ll go through a step-by-step example of implementing the Observer pattern. We’ll define a contract for the observers, create concrete implementations for both observers and the subject, and build a news system where subscribers receive updates about breaking news. This will help you grasp the practical application of the Observer pattern.

Let's break down the implementation step-by-step using our example.

Step 1: Define the Observer Interface
Kotlin
1interface Subscriber { 2 fun update(news: String) 3}

The Subscriber interface defines a contract for all observers. Any class implementing this interface must provide an implementation for the update method, which receives the updated information.

Step 2: Implement the Concrete Observer
Kotlin
1class NewsSubscriber(private val name: String) : Subscriber { 2 override fun update(news: String) { 3 println("$name received news: $news") 4 } 5}

Here, NewsSubscriber is a concrete implementation of the Subscriber interface. Each subscriber has a name and an update method that prints the received news.

Step 3: Define the Subject Interface
Kotlin
1interface NewsPublisher { 2 fun addSubscriber(subscriber: Subscriber) 3 fun removeSubscriber(subscriber: Subscriber) 4 fun notifySubscribers(news: String) 5}

The NewsPublisher interface lays out the methods for managing observers: adding, removing, and notifying subscribers. Any class that wants to act as a subject must implement these methods.

Step 4: Implement the Concrete Subject
Kotlin
1class NewsTopic : NewsPublisher { 2 private val subscribers: MutableList<Subscriber> = mutableListOf() 3 4 override fun addSubscriber(subscriber: Subscriber) { 5 subscribers.add(subscriber) 6 } 7 8 override fun removeSubscriber(subscriber: Subscriber) { 9 subscribers.remove(subscriber) 10 } 11 12 override fun notifySubscribers(news: String) { 13 for (subscriber in subscribers) { 14 subscriber.update(news) 15 } 16 } 17 18 // Method to simulate publishing news 19 fun publishNews(news: String) { 20 println("Publishing news: $news") 21 notifySubscribers(news) 22 } 23}

NewsTopic is a concrete implementation of the NewsPublisher interface. It maintains a list of subscribers and provides methods to add, remove, and notify them. The publishNews method simulates the action of broadcasting news to all subscribers.

Step 5: Using the Observer Pattern
Kotlin
1fun main() { 2 val newsTopic = NewsTopic() 3 4 val subscriber1 = NewsSubscriber("Subscriber 1") 5 val subscriber2 = NewsSubscriber("Subscriber 2") 6 7 newsTopic.addSubscriber(subscriber1) 8 newsTopic.addSubscriber(subscriber2) 9 10 newsTopic.publishNews("Breaking News 1") 11 newsTopic.removeSubscriber(subscriber1) 12 newsTopic.publishNews("Breaking News 2") 13}

In this Kotlin example, we create a NewsTopic instance and two subscribers. We add these subscribers to the NewsTopic, publish news updates, and observe the behavior of adding and removing subscribers.

The code above will produce the following output:

Plain text
1Publishing news: Breaking News 1 2Subscriber 1 received news: Breaking News 1 3Subscriber 2 received news: Breaking News 1 4Publishing news: Breaking News 2 5Subscriber 2 received news: Breaking News 2

Each publishNews method call will first print the news being published. Then, each subscriber will print the news it has received according to its update method. When Subscriber 1 is removed, only Subscriber 2 receives the subsequent news.

Why Is It Important?

The Observer pattern is incredibly useful for various reasons:

  1. Decoupling: It promotes loose coupling between the subject and the observers. The subject doesn't need to know specifics about the observers, only that they implement the Subscriber interface.
  2. Dynamic Relationships: Observers can be dynamically added or removed, making the system flexible and scalable.
  3. Real-time Updates: It ensures that all observers get updated state changes in real-time, making it ideal for applications like news feeds, stock price updates, and any scenario that requires immediate notifications.

Are you excited to put this into practice? Now it's your turn to try implementing the Observer pattern in Kotlin. Let's dive into the practice section and see how you can build a notification system using what you've learned!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.