Monday, January 28, 2013

"Observer" Design Pattern in Java

Introduction

The Java Platform used to have support for Observer design pattern in the form of Observer interface and Observable class starting from its initial release. However a long time passed since then. A lot of enhancements were added to the standard libraries and to the Java language itself. In this post I want to describe how generics and Java Collections Framework can be used together to build a better Observer design pattern implementation.

What’s wrong with Observer and Observable?

Before building a better implementation we need to identify the flaws of what we currently have. The JDK support for Observer design pattern has the following problems:
  1. It doesn’t use generics which are a must in the modern Java programming.
  2. Internally (at least when it comes to Oracle JDK 6 and JDK 7) Observable implementation uses synchronization inefficiently: it leverages Vector class which is synchronized by itself in addition to custom synchronization logic.
Let’s see how we can tackle the aforementioned issues using modern JDK facilities.

Observer Revised

The following subsections show how generics and Java Collections Framework can be leveraged to build modern Observer design pattern implementation.

Initial Implementation

First of all, we need to introduce generic analogues to standard JDK Observer interface and Observable class. Let them be EventListener and EventPublisher respectively:
// EventListener.java
public interface EventListener<
        P extends EventPublisher<P, L, E>,
        L extends EventListener<P, L, E>,
        E> {

    void handleEvent(P sender, E event);

}

// EventPublisher.java
public interface EventPublisher<
        P extends EventPublisher<P, L, E>,
        L extends EventListener<P, L, E>,
        E> {

    void addListener(L listener);

    void removeListener(L listener);

    void clearListeners();

    void publishEvent(E event);

}
Programming to interfaces instead of concrete classes is considered a good practice, that’s why Observable class has been replaced with a generic interface, not a generic class. The definitions of these interfaces may seem a bit weird at first glance. Let’s break them down to see what’s happening.

Let’s begin with the EventListener interface. We need to parameterize the type of event publisher to accept events from and the type of events to listen to. So we can start with the following definition:
// EventListener.java
public interface EventListener<P, E> {
    // ...
}
For EventPublisher interface we need to parameterize the type of event listener to notify and the type of events to publish. The following definition can be used to express this:
// EventPublisher.java
public interface EventPublisher<L, E> {
    // ...
}
It is known that every event publisher should implement EventPublisher interface and every event listener should implement EventListener interface. Let’s express this idea in code with type variable bounds:
// EventListener.java
public interface EventListener<P extends EventPublisher<???, E>, E> {
    // ...
}

// EventPublisher.java
public interface EventPublisher<L extends EventListener<???, E>, E> {
    // ...
}
This is invalid Java code of course. Triple question mark is used to indicate problems. Type variable P of EventListener is bounded by EventPublisher which is generic by itself. Hence we need to provide certain values (type arguments) for event type (E) and event listener (L) type variables of EventPublisher interface. The solution is trivial for event type: type variable E can be reused. But what should be passed as type argument for event listener?

Similar reasoning can be applied to EventPublisher interface. Type variable L of EventPublisher is bounded by EventListener which is generic by itself. Hence we need to provide certain values (type arguments) for event type (E) and event publisher (P) type variables of EventListener interface. The solution is trivial for event type: type variable E can be reused. But what should be passed as type argument for event publisher?

To solve the aforementioned problems and to convert the previous erroneous listing to the working Java code we need to introduce two more type variables:
  1. In EventListener interface definition L type variable will denote event listener type to notify. The only purpose of the L type variable is to serve as the type argument for EventPublisher interface which bounds P type variable of EventListener.
  2. In EventPublisher interface definition P type variable will denote event publisher to accept events from. The only purpose of the P type variable is to serve as the type argument for EventListener interface which bounds L type variable of EventPublisher.
In the end we have two generic interfaces with mutually recursive type variable bounds. The definitions of these interfaces now look similar to the ones at the beginning of this subsection:
// EventListener.java
public interface EventListener<
        P extends EventPublisher<P, L, E>,
        L extends EventListener<P, L, E>,
        E> {
    // ...
}

// EventPublisher.java
public interface EventPublisher<
        P extends EventPublisher<P, L, E>,
        L extends EventListener<P, L, E>,
        E> {
    // ...
}
And now let’s create AbstractEventPublisher – abstract base class which any event publisher can extend to avoid implementing EventPublisher interface from scratch:
// AbstractEventPublisher.java
public abstract class AbstractEventPublisher<
        P extends EventPublisher<P, L, E>,
        L extends EventListener<P, L, E>,
        E> implements EventPublisher<P, L, E> {

    private final List<L> listeners = new ArrayList<L>();

    @Override
    public void addListener(L listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(L listener) {
        listeners.remove(listener);
    }

    @Override
    public void clearListeners() {
        listeners.clear();
    }

    @Override
    @SuppressWarnings("unchecked")
    public void publishEvent(E event) {
        for (L listener : listeners) {
            listener.handleEvent((P) this, event);
        }
    }
}
There is nothing special about this class. The only thing worth noting is that it is not thread safe. This issue is tackled in the following subsection.

Naïve Thread-Safety

Quite often event publisher needs to be thread-safe. This subsection is the first try to implement thread-safety for AbstractEventPublisher class. It looks like this:
// AbstractEventPublisher.java
public abstract class AbstractEventPublisher<
        P extends EventPublisher<P, L, E>,
        L extends EventListener<P, L, E>,
        E> implements EventPublisher<P, L, E> {

    private final List<L> listeners =
            Collections.synchronizedList(new ArrayList<L>());

    @Override
    public void addListener(L listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(L listener) {
        listeners.remove(listener);
    }

    @Override
    public void clearListeners() {
        listeners.clear();
    }

    @Override
    @SuppressWarnings("unchecked")
    public void publishEvent(E event) {
        synchronized (listeners) {
            for (L listener : listeners) {
                listener.handleEvent((P) this, event);
            }
        }
    }
}
In this implementation field listeners is instantiated using synchronizedList() method. Iteration over listeners is contained inside the synchronized block as required by synchronizedList() contract.

Now AbstractEventPublisher class is thread-safe, but it has one serious flaw: it delivers events inside synchronized block. The code inside synchronized block should be as fast as possible because:
  1. No listener can be add/removed while iteration inside synchronized block is in progress.
  2. No other event can be delivered until handling of the currently delivered event is finished.
Depending on the activity performed inside handleEvent method implementation, calling it from synchronized block may lead to performance bottle-necks, exceptions, data corruptions or dead-locks. Joshua Bloch in his Effective Java book (item 67) names methods like handleEvent alien methods. It’s a very apt term because AbstractEventPublihser class has no idea of what event listeners might do as part of their handleEvent implementations. The next subsection shows how to protect against alien methods.

Using List Snapshot

One pretty obvious solution to alien methods problem is to make a copy (snapshot) of the field listeners inside synchronized block and deliver an event using that copy outside the block:
@Override
@SuppressWarnings("unchecked")
public void publishEvent(E event) {
    final List<L> snapshot = new ArrayList<L>();

    synchronized (listeners) {
        snapshot.addAll(listeners);
    }

    for (L listener : snapshot) {
        listener.handleEvent((P) this, event);
    }
}
This approach works fine and allows for avoiding alien methods, but a better alternative exists.

Using Concurrent List Implementation

Starting from Java 5 concurrent collections were introduced to the Java platform as part of the java.util.concurrent package. This package contains a lot of useful stuff to facilitate concurrent programs development. Class CopyOnWriteArrayList is the greatest interest for us. According to documentation it is a thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array. This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads. Hence CopyOnWriteArrayList class perfectly suits our needs:
// AbstractEventPublisher.java
public abstract class AbstractEventPublisher<
        P extends EventPublisher<P, L, E>,
        L extends EventListener<P, L, E>,
        E> implements EventPublisher<P, L, E> {

    private final List<L> listeners = new CopyOnWriteArrayList<L>();

    @Override
    public void addListener(L listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(L listener) {
        listeners.remove(listener);
    }

    @Override
    public void clearListeners() {
        listeners.clear();
    }

    @Override
    @SuppressWarnings("unchecked")
    public void publishEvent(E event) {
        for (L listener : listeners) {
            listener.handleEvent((P) this, event);
        }
    }
}
As you can see this code is almost identical to the very first implementation of abstract event publisher. The only difference is that CopyOnWriteArrayList is used instead of ArrayList to instantiate field listeners.

Practical Usage

Now let’s look at a practical example which incorporates all previously developed stuff. Assume we have class Circle which represents a circle and maintains its center, radius and color via instance fields. Suppose that Circle class instance should publish an event whenever any part of the instance state is changed. Let’s see how we can fulfill the aforementioned requirements based on the previously developed code.

First of all let’s look at the Circle class:
// Circle.java
public class Circle {
    private Point center;
    private int radius;
    private Color color;

    public Circle(Point center, int radius, Color color) {
        this.center = center;
        this.radius = radius;
        this.color = color;
    }

    public Point getCenter() {
        return center;
    }

    public void setCenter(Point center) {
        this.center = center;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }
}
There is nothing special about this class for now. It contains instance fields, getters and setters to retrieve and update instance fields, and a constructor to set initial object state.

Now let’s introduce two interfaces: CircleEvent and CircleEventListener. The first one is a tag interface which every event type published by the Circle class should implement. The second one as you might guess is supposed to be implemented by every circle event listener:
// CircleEvent.java
public interface CircleEvent {
}

// CircleEventListener.java
public interface CircleEventListener extends
        EventListener<Circle, CircleEventListener, CircleEvent> {
}
Remember that EventListener and EventPublisher interfaces have mutually recursive bounds. So in order to compile successfully and build on top of the AbstractEventPublisher class functionality Circle class definition should be modified like this:
// Circle.java
public class Circle extends AbstractEventPublisher<Circle,
        CircleEventListener, CircleEvent> {
// …
}
Now let’s look at the classes representing events itself. The Circle class should fire an event whenever its center, radius or color is changed. Hence there should be three different event types:
// CenterChangedEvent.java
public class CenterChangedEvent implements CircleEvent {
    private final Point oldCenter;
    private final Point newCenter;

    public CenterChangedEvent(Point oldCenter, Point newCenter) {
        this.oldCenter = oldCenter;
        this.newCenter = newCenter;
    }

    public Point getOldCenter() {
        return oldCenter;
    }

    public Point getNewCenter() {
        return newCenter;
    }
}

// ColorChangedEvent.java
public class ColorChangedEvent implements CircleEvent {
    private final Color oldColor;
    private final Color newColor;

    public ColorChangedEvent(Color oldColor, Color newColor) {
        this.oldColor = oldColor;
        this.newColor = newColor;
    }

    public Color getOldColor() {
        return oldColor;
    }

    public Color getNewColor() {
        return newColor;
    }
}

// RadiusChangedEvent.java
public class RadiusChangedEvent implements CircleEvent {
    private final int oldRadius;
    private final int newRadius;

    public RadiusChangedEvent(int oldRadius, int newRadius) {
        this.oldRadius = oldRadius;
        this.newRadius = newRadius;
    }

    public int getOldRadius() {
        return oldRadius;
    }

    public int getNewRadius() {
        return newRadius;
    }
}
All three event classes are designed to be immutable. Each one contains old and new value of the corresponding Circle class instance field. Now let’s include event publishing code in the Circle class setters.
// Circle.java
public class Circle extends AbstractEventPublisher<Circle,
        CircleEventListener, CircleEvent> {

    // …

    public void setCenter(Point center) {
        if (!this.center.equals(center)) {
            publishEvent(new CenterChangedEvent(this.center, center));
        }

        this.center = center;
    }

    public void setRadius(int radius) {
        if (this.radius != radius) {
            publishEvent(new RadiusChangedEvent(this.radius, radius));
        }

        this.radius = radius;
    }

    public void setColor(Color color) {
        if (!this.color.equals(color)) {
            publishEvent(new ColorChangedEvent(this.color, color));
        }

        this.color = color;
    }
}
As you can see Circle class setters publish events using inherited publishEvent method. We’re almost done. To make sure everything works as expected let’s develop a simple circle event handler which will just print relevant message to the console:
// SimpleCircleEventHandler.java
public class SimpleCircleEventHandler implements CircleEventListener {

    private Map<Class<? extends CircleEvent>,
            CircleEventListener> handlers;

    public SimpleCircleEventHandler() {
        handlers = new HashMap<Class<? extends CircleEvent>,
                CircleEventListener>();
        
        handlers.put(CenterChangedEvent.class,
                new CenterChangedEventHandler());
        handlers.put(ColorChangedEvent.class,
                new ColorChangedEventHandler());
        handlers.put(RadiusChangedEvent.class,
                new RadiusChangedEventHandler());
    }

    @Override
    public void handleEvent(Circle sender, CircleEvent event) {
        CircleEventListener handler = handlers.get(event.getClass());

        if (handler != null) {
            handler.handleEvent(sender, event);
        }
    }

    private static class CenterChangedEventHandler implements
            CircleEventListener {
        
        @Override
        public void handleEvent(Circle sender, CircleEvent e) {
            CenterChangedEvent event = (CenterChangedEvent) e;
            String message = "center changed from %s to %s"
            System.out.println(String.format(message,
                    event.getOldCenter().toString(),
                    event.getNewCenter().toString()));
        }
    }

    private static class ColorChangedEventHandler implements
            CircleEventListener {
        
        @Override
        public void handleEvent(Circle sender, CircleEvent e) {
            ColorChangedEvent event = (ColorChangedEvent) e;
            String message = "color changed from %s to %s"
            System.out.println(String.format(message,
                    event.getOldColor().toString(),
                    event.getNewColor().toString()));
        }
    }

    private static class RadiusChangedEventHandler implements
            CircleEventListener {
        
        @Override
        public void handleEvent(Circle sender, CircleEvent e) {
            RadiusChangedEvent event = (RadiusChangedEvent) e;
            String message = "radius changed from %d to %d"
            System.out.println(String.format(message,
                    event.getOldRadius(), event.getNewRadius()));
        }
    }
}
And finally there is a small main program to wire up everything together:
// ObserverMain.java
public class ObserverMain {
    public static void main(String[] args) {
        Circle circle = new Circle(new Point(10, 10), 15, Color.RED);
        circle.addListener(new SimpleCircleEventHandler());

        circle.setCenter(new Point(5, 5));
        circle.setRadius(20);
        circle.setColor(Color.GREEN);
    }
}
This program will print the following output:

center changed from java.awt.Point[x=10,y=10] to java.awt.Point[x=5,y=5]
radius changed from 15 to 20
color changed from java.awt.Color[r=255,g=0,b=0] to java.awt.Color[r=0,g=255,b=0]

Conclusion

Ok, that’s it. As you can see, modern Java allows for building better and more type safe Observer design pattern implementations compared to standard JDK facilities. Of course it didn’t become as smooth as it should be (compared to events in C# for example), but one day it will certainly do :)

Thanks for reading,
See you soon!

1 comment:

  1. Actually, this still isn't quite thread safe. If two threads call setColor(), for example, the events could be published in the opposite order than the color gets set. The observers, therefore, could think the final color is red, but in fact it is green. The above code is fine (and very elegant) under the assumption that the methods that change the state of the object (like setColor()) are only called from one thread. See [Lee, The Problem with Threads, IEEE Computer, May 2006].

    ReplyDelete