Introduction to the Observer Pattern

Welcome back! We're continuing our exploration of Behavioral Patterns. In this lesson, we will delve into the Observer Pattern, another fundamental pattern that emphasizes object communication and responsibility distribution. This pattern allows an object, known as the subject, to maintain a list of its dependents, called observers, and notify them automatically of any state changes, usually by calling one of their methods.

Previously, we looked at the Command Pattern, which encapsulates a request as an object. Now, let's build on that knowledge and explore how the Observer Pattern facilitates communication between objects in a seamless and efficient manner.

Core Components of the Observer Pattern

Let's break down the process into clear steps to implement the Observer Pattern.

Step 1: Define the Observer

Start by defining the Observer interface, which specifies the contract for receiving updates. In TypeScript, interfaces are commonly used for this purpose, and we can specify the type of the parameter in the update method.

In this code snippet, the Subscriber interface defines the update method, which takes a news string as a parameter. Any class that implements this interface must provide its own implementation of the update method.

Step 2: Create the Subject

Next, create the NewsPublisher class, which acts as the Subject. This class maintains a list of subscribers and provides methods to add and remove subscribers, as well as to notify them. In TypeScript, we add type annotations for the subscribers array and method parameters.

The NewsPublisher class has three methods: addSubscriber to add a new subscriber, removeSubscriber to remove an existing subscriber, and publish to notify all subscribers of new news. All parameters and properties are explicitly typed.

Step 3: Implement a Concrete Observer

Now, implement a concrete observer, which in this case will be a specific type of subscriber. This observer will define how to handle the updates received from the subject. The class explicitly implements the Subscriber interface and uses type annotations.

The ConcreteSubscriber class implements the Subscriber interface and provides its own implementation of the update method to print the news received. The name property is typed as a string.

Step 4: Client Code

Finally, see how these components work together in a script execution context, which serves as the client in this pattern. All variables are explicitly typed, and the code is written in TypeScript.

In the main function, an instance of NewsPublisher is created along with two ConcreteSubscriber objects. These subscribers are added to the publisher's list, and when the publisher's publish method is called, all subscribers receive notifications of the news. After demonstrating the notification process, one subscriber is removed, and a second news publication is executed to show that only the remaining subscriber receives the update, illustrating the dynamic nature of the Observer Pattern.

Full Code Example

Here is the complete code put together in TypeScript:

Conclusion

Mastering the Observer Pattern is crucial for designing systems where objects need to maintain synchronized states. This pattern promotes loose coupling, enhances code readability, and improves maintainability.

Consider a news publishing system in which multiple subscribers (users) receive updates whenever new articles are published. The Observer Pattern ensures that all subscribers are automatically notified of the new news without the publisher needing to maintain direct dependencies on each subscriber. This design greatly simplifies future system extensions, as new subscriber types can be added without modifying existing code.

The Observer Pattern unlocks the ability to create highly responsive and well-structured software systems. Let's move on to the practice section and see these concepts in action!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal