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.
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.
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.
Kotlin1interface 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.
Kotlin1class 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.
Kotlin1interface 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.
Kotlin1class 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.
Kotlin1fun 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 text1Publishing 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.
The Observer pattern is incredibly useful for various reasons:
- 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. - Dynamic Relationships: Observers can be dynamically added or removed, making the system flexible and scalable.
- 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!