한국어 | English | 日本語
Senior Web Application Developer (8.8+ years)
Tech & Dev
engineering
Focusing on web frontend and backend development

5. Observer Pattern

How do you track the frequently changing state of variables? Beyond simply checking manually, we explore an efficient mechanism for exchanging state changes in real-time while minimizing dependencies between objects.
Understand the operating principles of the publish-subscribe model centered around the Observable and Observer interfaces, learn the differences between Push and Pull data delivery methods, and grasp design principles for reducing coupling between objects.

Variables

When we first learn programming, we start with variables. Values that do not change are called constants, while the values of variables change frequently. Because variables can change constantly, they literally go through many challenges throughout the program’s lifecycle.

State

As mentioned above, variables can have many different states. There are two ways to know the state of these variables.

Push Method

Automatic: The variable itself notifies us when its state has changed.

Pull Method

Manual: We actively check if the variable’s state has changed.

Being notified automatically might seem the most convenient, but it would be quite annoying if a variable kept telling us its state even when we don’t need to know. Resources for continuously tracking that state would also be unnecessarily wasted. In such cases, a manual method, where we can check the state only when needed, is also necessary. These are somewhat formally referred to as Push and Pull methods. If we consider the state of a variable as a ‘topic’, then the way we learn about its state is divided into whether it notifies us (Push method) or we actively check (Pull method).

Observer Pattern

The Observer Pattern is a design pattern that allows us to know the state of a variable (using either the Push or Pull method as desired).

Observer Shorthand

Typically, when explaining this pattern, the state is considered a ‘topic’ and it’s described as a Publish-Subscribe model. However, since the pattern’s name is Observer Pattern, to avoid confusion, I will explain it using only two terms: Observer and Observable, rather than the publish-subscribe model terminology. As mentioned earlier, there are only two types of interfaces in the Observer Pattern. One is the Observable, which possesses the state, and the other is the Observer, which intends to view the state.

Observable

Looking at the Observer Pattern diagram above, the Observable interface has two pieces of information:

It’s important not to misunderstand: the Observable interface doesn’t is the state itself, but has the state. The term ‘Observable’ signifies that it ‘has’ the state, meaning that an Observer can ‘observe’ the state through this Observable interface. Furthermore, an Observable manages the Observers that want to be notified of or check its state in a list (though other data structures are also possible). This allows it to decide, for the Push method, to whom the state should be sent? And, for the Pull method, who is allowed to view the state?

interface Observable {
    protected List<Observer> observers; // In Java, this would typically be an instance variable in an implementing class.
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObserver(Object obj);
}
class StateObservable implements Observable {
    private State state; // Assuming 'State' is a defined class or type
    private List<Observer> observers = new ArrayList<>(); // A common way to manage observers

    public void changeState() { /* State changes. */ }

    @Override
    public void registerObserver(Observer o) { /* Add observer */ observers.add(o); }
    @Override
    public void removeObserver(Observer o) { /* Remove observer */ observers.remove(o); }
    // This method is for the Push model. The 'State' type is often used here.
    public void notifyObserver(State state) { /* 2. Transmit 1. the state to each observer in the observer list. */
        for (Observer o : observers) {
            // Assuming the Observer has an 'update' method to receive the state.
            // o.update(state);
        }
    }
}
    // In a pure Pull model, observers actively poll, so this method typically does nothing
    // or acts as a generic notification for observers to pull data.
    @Override
    public void notifyObserver(Object obj) { /* Does nothing. */ }
    public State getState() { /* Observers can call this method to retrieve the state. */ return state; }
}

Observer

Without much elaboration, the Observer is an interface for intending to view a state. As it is an interface, if you wish to view and utilize the relevant information, you can implement and use it in any way that suits your intent.

interface Observer {
    protected Observable observable; // In Java, this would typically be an instance variable in an implementing class.
    public void getStateFromObservable(); // This method indicates a Pull mechanism.
}
class StateObserver implements Observer {
    private State state;
    private Observable observable;

    public StateObserver(Observable observable) {
        this.observable = observable;
        this.observable.registerObserver(this);
    }

    // This method is commonly used in a Push-style update,
    // although the Observer interface here defines getStateFromObservable().
    public void update(State state) { // Assuming State type, often called by Observable.notifyObserver()
        this.state = state;
    }

    @Override // Implementation for the Pull model as per the interface
    public void getStateFromObservable() {
        // This is where the observer pulls the state using its observable reference.
        // Example: this.state = observable.getState();
    }
}

Why was StateObserver added by passing the Observable into its constructor and registering it there, instead of using Observable.getObservers().add(new StateObserver())?

By not calling Observable.getObservers(), the observer list is never exposed outside the Observable.


Why was the Observer Pattern formally defined as a pattern? It might seem unnecessarily complex. Its significance lies in the fact that the two interfaces, Observable and Observer, can exchange data without needing to know anything about each other’s implementations. To elaborate further, it’s as follows:

The principle is to keep both the state held by the Observable and the observer table unexposed to the outside world, allowing only the observers to be aware of them. This aligns with the principle: “Objects that interact with each other should be as loosely coupled as possible.”

I hope this was well understood. We will conclude today’s design pattern discussion here.


5. Observer Pattern
Author
Aaron
Posted on
Licensed Under
CC BY-NC-SA 4.0
CC BY-NC-SA 4.0
More in this category
Recent posts
The Erosion of Conversational Muscle and Communication Styles by LLM Filters
In an era where LLM tools, which filter out conversational impoliteness and deliver refined responses, have become commonplace, are we truly engaging in more thoughtful conversations? This article examines the phenomenon of conversational ability, which should be honed through countless failures in real-time communication, degenerating due to reliance on external tools. It further explores the potential societal anxieties and shifts in generational behavioral patterns that this trend may bring.
Optimal Timing and Strategy for Salary Negotiation with Senior Candidates
Salary negotiation is more than just an exchange of figures; it's a strategic dance of psychological timing. This analysis explores why engaging in a gradual negotiation process from the initial stages of recruitment, rather than waiting until after a final offer (when candidates tend to adopt a more calculative stance), proves more efficient for companies and fosters a more honest sharing of resources.
The Limits of the Rule of Law and Human Diversity
The belief that all human actions can be regulated by a single legal system may be an act of hubris. This article offers a sharp analysis of the paradox of the rule of law faced by humanity, which, having escaped the hierarchical controls of the Middle Ages, has now embraced infinite modern freedom. It further examines the deepening social coercion and the demonization of others that arise under the guise of diversity.
토스트 예시 메세지