Fundamentals 7 min read

Observer Pattern in Java: Decoupled Event Notification with E-Commerce Example

This tutorial explains the Observer design pattern with a Java implementation using an e-commerce order system where payment triggers logistics and procurement updates, demonstrating loose coupling between subject and observers.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Observer Pattern in Java: Decoupled Event Notification with E-Commerce Example

Observer Pattern Overview

The Observer pattern is a behavioral design pattern that defines a one-to-many dependency between objects so that when one object (the subject) changes state, all its dependents (observers) are notified and updated automatically.

Pattern Roles

Subject (also called Observable): Maintains a list of observers and provides methods to register, remove, and notify them.

Observer : Defines an update interface that is called when the subject changes.

ConcreteSubject : Implements the subject interface, stores state, and notifies observers when state changes.

ConcreteObserver : Implements the observer interface and performs specific actions in response to subject notifications.

E-Commerce Scenario

The article illustrates the pattern with an order management system. When an order is paid (state changes to "paid"), the logistics system must ship the goods and the procurement system must restock. The order acts as the subject; logistics and procurement are observers.

Java Implementation

Observer Interface

package com.sample.patterns.observer;
// Abstract observer
public interface Observer {
    // Update operation for observers
    void update();
}

Order (Subject) Interface

package com.sample.patterns.observer;
// Order interface, acts as subject
public interface Order {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObserver();
}

ConcreteSubject: CustomerOrder

package com.sample.patterns.observer;
import java.util.ArrayList;
import java.util.List;
// Concrete subject class
public class CustomerOrder implements Order {
    private List<Observer> list = new ArrayList();
    // Order state: 0 = unpaid; 1 = paid
    private int state = 0;
    public int getState() {
        return state;
    }
    public void setState(int state) {
        this.state = state;
        notifyObserver();
    }
    @Override
    public void registerObserver(Observer observer) {
        list.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        list.remove(observer);
    }
    @Override
    public void notifyObserver() {
        for (Observer observer : list) {
            observer.update();
        }
    }
}

ConcreteObserver: LogisticsObserver

package com.sample.patterns.observer;
// Observer: Logistics system
public class LogisticsObserver implements Observer {
    private int state;
    private CustomerOrder order;
    public LogisticsObserver(CustomerOrder order) {
        this.order = order;
        this.order.registerObserver(this);
    }
    @Override
    public void update() {
        this.state = order.getState();
        System.out.println("Observer state updated to: " + this.state);
        // If state becomes paid, start transport
        if (this.state == 1) {
            System.out.println("Begin to transport!");
        }
    }
}

ConcreteObserver: PurchaseObserver

package com.sample.patterns.observer;
// Observer: Procurement system
public class PurchaseObserver implements Observer {
    private int state;
    private CustomerOrder order;
    public PurchaseObserver(CustomerOrder order) {
        this.order = order;
        this.order.registerObserver(this);
    }
    @Override
    public void update() {
        this.state = order.getState();
        System.out.println("Observer state updated to: " + this.state);
        // If state becomes paid, start procurement
        if (this.state == 1) {
            System.out.println("Begin to purchase!");
        }
    }
}

Client Test

package com.sample.patterns.observer;
// Test client
public class Client {
    public static void main(String[] args) {
        CustomerOrder order = new CustomerOrder();
        LogisticsObserver logisticsObserver = new LogisticsObserver(order);
        PurchaseObserver purchaseObserver = new PurchaseObserver(order);
        order.setState(1);
    }
}

Output

Running the client produces:

Console output showing observer state updated to 1, Begin to transport!, Begin to purchase!
Console output showing observer state updated to 1, Begin to transport!, Begin to purchase!

Conclusion

The Observer pattern decouples the subject from its observers, making it suitable for one-to-many scenarios where state changes must be propagated. Adding new observers only requires implementing the Observer interface and registering with the subject.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

design patternsJavasoftware architectureObserver PatternDecouplingEvent NotificationBehavioral Pattern
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.