Implementing the Observable Pattern in JavaScript
The Observable pattern is a behavioral design pattern that allows one object (the subject) to notify multiple observers of any state changes. This is a fundamental pattern for building reactive systems and event-driven architectures, commonly used in UI frameworks and data synchronization. Your task is to implement a basic Observable pattern in JavaScript.
Problem Description
You need to create a JavaScript class named Observable that allows objects to subscribe to and unsubscribe from notifications when its state changes. The Observable class should provide the following functionalities:
subscribe(observer): Adds an observer to the list of observers. An observer is an object with anextmethod that will be called when the observable emits a new value.unsubscribe(observer): Removes an observer from the list of observers.notify(value): Iterates through all subscribed observers and calls theirnextmethod with the providedvalue.getState(): Returns the current state of the observable.setState(newState): Sets the state of the observable and triggers notifications to all subscribed observers.
The observer object passed to subscribe must have a next method. If it doesn't, the subscribe method should do nothing.
Examples
Example 1:
Input:
observable = new Observable();
observer1 = { next: (value) => console.log("Observer 1:", value) };
observer2 = { next: (value) => console.log("Observer 2:", value) };
observable.subscribe(observer1);
observable.subscribe(observer2);
observable.setState("Initial State");
observable.setState("New State");
Output:
Observer 1: New State
Observer 2: New State
Explanation:
Two observers are subscribed. When `setState` is called with "New State", both observers' `next` methods are called with this value.
Example 2:
Input:
observable = new Observable();
observer1 = { next: (value) => console.log("Observer 1:", value) };
observer2 = { next: (value) => console.log("Observer 2:", value) };
observable.subscribe(observer1);
observable.unsubscribe(observer1);
observable.setState("Updated State");
Output:
(No output)
Explanation:
Observer 1 is subscribed, then immediately unsubscribed. Therefore, when `setState` is called, only the (non-existent) observer 2 would be notified, and since it's not there, nothing is logged.
Example 3: (Edge Case - Invalid Observer)
Input:
observable = new Observable();
observer1 = {}; // No 'next' method
observable.subscribe(observer1);
observable.setState("State Change");
Output:
(No output)
Explanation:
The observer passed to `subscribe` does not have a `next` method. The `subscribe` method should gracefully handle this and not throw an error or attempt to call a non-existent method.
Constraints
- The
Observableclass should be implemented using JavaScript's prototype-based inheritance (no ES6 classes are required, though they are acceptable). - The
notifymethod should not throw an error if there are no observers. - The
setStatemethod should always trigger notifications, even if the new state is the same as the old state. - The
subscribemethod should not modify the observer object passed to it. - The
unsubscribemethod should handle the case where the observer is not currently subscribed. It should not throw an error.
Notes
- Consider using an array to store the list of observers.
- The
nextmethod of the observer is the only method that needs to be defined. You can add other methods to the observer object as needed. - This is a simplified implementation of the Observable pattern. Real-world implementations often include error handling, more sophisticated observer management, and support for different types of events.
- Focus on the core functionality of subscribing, unsubscribing, and notifying observers. Don't worry about advanced features like error handling or asynchronous notifications.