1. Definition

The Observer pattern is a behavioral design pattern where an object (known as the subject) maintains a list of its dependents (observers) and notifies them of any state changes, usually by calling one of their methods.

2. Problem Statement

Consider a scenario where multiple entities need to be informed whenever a particular object changes its state. Directly interlinking these entities to the main object would lead to tightly coupled systems, making modifications and expansions challenging.

3. Solution

The Observer pattern addresses this problem by introducing a layer of abstraction: observers that watch the subject. When the subject’s state changes, it notifies all its observers about the change.

4. Real-World Use Cases

1. News publishers and subscribers: Subscribers get notified when a new article is published.

2. Auction system: Bidders (observers) get notified if a new bid exceeds the current bid.

5. Implementation Steps

1. Define the Observer interface with a method that is called to get updated.

2. Define the Subject interface with methods to register, unregister, and notify its observers.

3. Implement concrete classes for the Observer and Subject interfaces.

6. Implementation in Java

// Observer Interface
interface Observer {
    void update(String message);
}

// Concrete Observer
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

// Subject Interface
interface Subject {
    void register(Observer observer);
    void unregister(Observer observer);
    void notifyObservers(String message);
}

// Concrete Subject
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void register(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void unregister(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

// Client
public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");

        subject.register(observer1);
        subject.register(observer2);

        subject.notifyObservers("Hello, Observers!");
    }
}

Output:

Observer 1 received message: Hello, Observers!
Observer 2 received message: Hello, Observers!

Explanation:

The ConcreteObserver implements the Observer interface and defines how to get updated. The ConcreteSubject maintains a list of observers and is responsible for registering, unregistering, and notifying observers of changes. In the client code, we created two observers and registered them with the subject. When the subject's state changes (a new message in this case), all registered observers get notified.

7. When to use?

1. When a change to one object requires changing others and you don’t know how many objects need to be changed.

2. When an object should notify other objects without making assumptions about who these objects are.