MTI TEK
  • Home
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All Resources
Java Design Patterns | Observer
  1. Overview and Definition
  2. Class Diagram
  3. Implementation Example
    • The Observer Interface
    • The Concrete Observer
    • The Abstract Subject
    • The Concrete Subject
    • Testing the Observer Pattern

  1. Overview and Definition
    The Observer pattern is a behavioral design pattern that defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. It establishes a subscription mechanism to notify multiple objects about any events that happen to the object they're observing.

    Key Components:
    • Observer: Defines the interface for objects that should be notified of changes in the subject.
    • Concrete Observer: Implements the Observer interface and maintains a reference to the subject to receive notifications.
    • Subject: Defines the interface for attaching and detaching Observer objects and notifying them of changes.
    • Concrete Subject: Stores state and notifies observers when the state changes.

    Benefits:
    • Loose Coupling: The subject and observers are loosely coupled, with the subject knowing only that observers implement the Observer interface.
    • Dynamic Relationships: Observers can be added or removed at runtime, allowing for flexible subscription management.
    • Broadcast Communication: A single subject can notify multiple observers simultaneously when its state changes.
  2. Class Diagram
    Observer Pattern Components:
    • Observer: Observer interface - defines the notification interface for objects that should be updated.
    • Concrete Observer: Client class - receives notifications and reacts to state changes in the subject.
    • Subject: Observable abstract class - manages observers and provides notification mechanism.
    • Concrete Subject: Server class - maintains state and notifies observers when state changes.
    ┌─────────────────────────────┐
    │       <<interface>>         │
    │         Observer            │  ← Observer
    ├─────────────────────────────┤
    │ + update(Observable): void  │
    └─────────────────────────────┘
                  △
                  │ implements
                  │
    ┌─────────────────────────────┐
    │          Client             │  ← Concrete Observer
    ├─────────────────────────────┤
    │ - id: String                │
    │ + Client(String)            │
    │ + update(Observable): void  │
    └─────────────────────────────┘
    
    
    ┌─────────────────────────────┐
    │       <<abstract>>          │
    │        Observable           │  ← Subject
    ├─────────────────────────────┤
    │ - observers: List<Observer> │
    │ + add(Observer): void       │
    │ + remove(Observer): void    │
    │ + notifyObservers(): void   │
    │ + getId(): String           │
    └─────────────────────────────┘
                  △
                  │ extends
                  │
    ┌─────────────────────────────┐
    │          Server             │  ← Concrete Subject
    ├─────────────────────────────┤
    │ - id: String                │
    │ - state: Boolean            │
    │ + Server(String, Boolean)   │
    │ + setState(boolean): void   │
    │ + getState(): boolean       │
    └─────────────────────────────┘
                    
  3. Implementation Example
    • The Observer Interface:
      The Observer interface defines the contract for objects that want to be notified of changes in the subject. All concrete observers must implement this interface to receive notifications.
      public interface Observer {
          void update(final Observable observable);
      }
    • The Concrete Observer:
      The Concrete Observer implements the Observer interface and defines how to react when notified of changes. It receives the observable object as a parameter and can query its state when updated.
      public class Client implements Observer {
          private final String id;
      
          public Client(final String id) {
              this.id = id;
          }
      
          public String getId() {
              return id;
          }
      
          public void update(final Observable observable) {
              if (observable instanceof Server) {
                  Server server = (Server) observable;
                  System.out.println("[Client '" + id + "'] Server '" + server.getId() + "' - State: " + server.getState());
              }
          }
      }
    • The Abstract Subject:
      The Abstract Subject provides the common functionality for managing observers. It maintains a list of observers and provides methods to add, remove, and notify them.
      public abstract class Observable {
          final List<Observer> observers = new ArrayList<>();
      
          public void add(final Observer observer) {
              observers.add(observer);
          }
      
          public void remove(final Observer observer) {
              observers.remove(observer);
          }
      
          public void notifyObservers() {
              for (final Observer observer : observers) {
                  observer.update(this);
              }
          }
      
          public abstract String getId();
      }
    • The Concrete Subject:
      The Concrete Subject extends the Abstract Subject and maintains the actual state that observers are interested in. When the state changes, it automatically notifies all registered observers.
      public class Server extends Observable {
          private final String id;
          private Boolean state;
      
          public Server(final String id, final Boolean state) {
              this.id = id;
              this.state = state;
          }
      
          public String getId() {
              return id;
          }
      
          public boolean getState() {
              return state;
          }
      
          public void setState(final boolean state) {
              this.state = state;
              notifyObservers();
          }
      }
    • Testing the Observer Pattern:
      The client code demonstrates how observers are automatically notified when the subject's state changes. It shows adding observers, triggering notifications, and removing observers dynamically.
      public class ObserverPatternTest {
          public static void main(String[] args) {
              final Server server1 = new Server("server1", Boolean.TRUE);
      
              final Client client1 = new Client("client1");
              final Client client2 = new Client("client2");
      
              // add observers
              server1.add(client1);
              server1.add(client2);
      
              // notify observers: client1, client2
              System.out.println("-- Notify observers:");
              server1.setState(Boolean.FALSE);
      
              // remove observer: client2
              System.out.println("-- Remove observers: client2");
              server1.remove(client2);
      
              // notify observers: client1
              System.out.println("-- Notify observers:");
              server1.setState(Boolean.TRUE);
          }
      }
© 2025 mtitek