# How to Implement the Observer Pattern Using Java PropertyChangeSupport

> Implement the Observer pattern in Java using PropertyChangeSupport. Effortlessly manage listeners and fire change events with old and new values for robust notifications.

- Repository: [Ilkka Seppälä/java-design-patterns](https://github.com/iluwatar/java-design-patterns)
- Tags: how-to-guide
- Published: 2026-02-27

---

**Use `java.beans.PropertyChangeSupport` to manage listener registration and event firing, eliminating manual list management while providing rich change notifications with old and new values.**

The Observer pattern decouples subjects from observers, but hand-rolling listener lists adds boilerplate and thread-safety concerns. The `iluwatar/java-design-patterns` repository demonstrates this pattern in [`Weather.java`](https://github.com/iluwatar/java-design-patterns/blob/main/Weather.java) and [`WeatherObserver.java`](https://github.com/iluwatar/java-design-patterns/blob/main/WeatherObserver.java), yet you can modernize the implementation by leveraging the JDK's built-in `PropertyChangeSupport` class to handle the observer infrastructure.

## Why Use PropertyChangeSupport for the Observer Pattern?

The standard implementation in [`Weather.java`](https://github.com/iluwatar/java-design-patterns/blob/main/Weather.java) maintains a `List<WeatherObserver>` and manually iterates to notify observers. Switching to `PropertyChangeSupport` offers three concrete advantages:

- **Reduced boilerplate**: The support class manages the listener list, synchronization, and iteration logic internally.
- **Rich event metadata**: Observers receive `PropertyChangeEvent` objects containing the property name, old value, and new value.
- **JavaBeans compliance**: Integrates with visual editors, serialization frameworks, and other beans-aware tooling.

## Step-by-Step Implementation Guide

Follow these steps to refactor the `Weather` class from the `iluwatar/java-design-patterns` repository to use `PropertyChangeSupport` while preserving backward compatibility with the existing `WeatherObserver` interface.

### Add PropertyChangeSupport to the Subject

In [`Weather.java`](https://github.com/iluwatar/java-design-patterns/blob/main/Weather.java), declare a `PropertyChangeSupport` field initialized with the subject instance as the source:

```java
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;

public class Weather {
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    // existing fields...
}

```

### Expose Listener Registration Methods

Delegate add and remove operations to the support object. These methods follow the JavaBeans convention:

```java
public void addPropertyChangeListener(PropertyChangeListener listener) {
    pcs.addPropertyChangeListener(listener);
}

public void removePropertyChangeListener(PropertyChangeListener listener) {
    pcs.removePropertyChangeListener(listener);
}

```

### Fire Property Change Events

Modify the `timePasses()` method to fire events whenever the weather state changes. Capture the old value before updating the state:

```java
public void timePasses() {
    var enumValues = WeatherType.values();
    var oldWeather = this.currentWeather;
    this.currentWeather = enumValues[(this.currentWeather.ordinal() + 1) % enumValues.length];
    
    // Notify legacy observers
    notifyObservers();
    
    // Fire PropertyChangeEvent with property name, old value, and new value
    pcs.firePropertyChange("weather", oldWeather, this.currentWeather);
}

```

### Implement PropertyChangeListener in Observers

Create a new observer class that implements `java.beans.PropertyChangeListener` instead of the custom `WeatherObserver` interface:

```java
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class WeatherChangeLogger implements PropertyChangeListener {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        System.out.printf("Property '%s' changed from %s to %s%n",
            evt.getPropertyName(),
            evt.getOldValue(),
            evt.getNewValue());
    }
}

```

## Complete Integration Example

The following client code demonstrates registering both legacy `WeatherObserver` instances and new `PropertyChangeListener` implementations simultaneously:

```java
public class WeatherMonitoringSystem {
    public static void main(String[] args) {
        Weather weather = new Weather();
        
        // Legacy observer
        weather.addObserver(new Orcs());
        weather.addObserver(new Hobbits());
        
        // Modern PropertyChangeListener
        weather.addPropertyChangeListener(new WeatherChangeLogger());
        
        // Trigger state changes
        weather.timePasses();
        weather.timePasses();
    }
}

```

## Comparing Custom Observer vs. PropertyChangeSupport

| Feature | Custom Implementation ([`Weather.java`](https://github.com/iluwatar/java-design-patterns/blob/main/Weather.java)) | `PropertyChangeSupport` Approach |
|---------|--------------------------------------|----------------------------------|
| **Listener Management** | Manual `ArrayList<WeatherObserver>` with add/remove methods | Built-in synchronized listener list |
| **Event Payload** | Custom `WeatherType` passed directly | `PropertyChangeEvent` with property name, old value, new value |
| **Thread Safety** | Requires manual synchronization | Thread-safe listener addition/removal |
| **JavaBeans Compliance** | Non-standard | Standard JavaBeans event pattern |
| **Refactoring Effort** | Baseline | Minimal—wrap existing notify logic |

## Summary

- **PropertyChangeSupport** eliminates boilerplate listener list management while adding rich metadata to change notifications.
- Integrate the support class by adding it as a field in your subject, delegating registration methods, and firing events in state-change methods.
- The `iluwatar/java-design-patterns` repository's `Weather` class can be extended to support both the legacy `WeatherObserver` interface and the standard `PropertyChangeListener` for maximum flexibility.
- This approach provides thread-safe operations and aligns with JavaBeans conventions, making your observer implementation compatible with frameworks that rely on standard event patterns.

## Frequently Asked Questions

### What is the difference between PropertyChangeSupport and the custom Observer interface in the java-design-patterns repository?

The custom `WeatherObserver` interface in the repository defines a specific contract with an `update(WeatherType)` method, requiring the subject to maintain a list of observers manually. `PropertyChangeSupport` is a JDK utility class that manages listener registration internally, fires `PropertyChangeEvent` objects containing property names and old/new values, and provides thread-safe operations without custom list management code.

### Can I use PropertyChangeSupport while keeping the existing WeatherObserver implementations?

Yes, you can maintain backward compatibility by keeping the existing `List<WeatherObserver>` and `notifyObservers()` logic while adding `PropertyChangeSupport` for new functionality. Call `pcs.firePropertyChange()` immediately after notifying legacy observers in your state-change methods. This allows gradual migration where legacy observers receive direct updates while new components consume standard `PropertyChangeEvent` objects.

### Is PropertyChangeSupport thread-safe for adding and removing listeners?

Yes, `PropertyChangeSupport` provides thread-safe operations for adding and removing listeners through synchronized internal data structures. However, the actual notification of listeners (firing events) is not synchronized by default to prevent deadlocks. If you require atomic notification across multiple property changes or need to ensure observers see consistent state, you should synchronize the firing logic externally or use `PropertyChangeSupport`'s constructor that accepts a source object and ensure proper synchronization in your subject class.

### When should I choose PropertyChangeSupport over RxJava or other reactive libraries?

Choose `PropertyChangeSupport` when building JavaBeans-compliant components, integrating with legacy Swing/JavaFX property binding, or when you need a lightweight, JDK-only solution without external dependencies. It is ideal for simple property change notifications within a single JVM. Choose RxJava or Project Reactor when you need complex stream operations (filtering, mapping, combining), backpressure handling, cross-thread scheduling, or integration with reactive web frameworks. `PropertyChangeSupport` is synchronous and single-purpose, while reactive libraries provide composable asynchronous event streams.