Your Guide to Design Patterns – Observer Pattern

Design Patterns Observer Pattern

This week we’ll continue our exploration of design patterns and look at a commonly used behavioural pattern, the Observer pattern.

The Observer Pattern

The Gang of Four book defines the Observer pattern as follows:

“Define a one-to-many dependency between objects so that one object changes state, all its dependents are notified and updated automatically.”

The Observer design pattern is useful when we’re interested in the state of an object and want to be notified whenever there’s any change in its state.

One of the most common uses for the Observer pattern is when we code event listeners in applications with graphical user interfaces (GUIs).

Structure

The Observer pattern consists of the following participants:

  • The object that watches the state of another object is called the Observer.
  • The object being watched is called the Subject. A subject may have any number of observers. All observers are notified whenever the subject changes state.

The Observer pattern is also known as Publish-Subscribe. The subject is the publisher. It sends out notifications without having to know who its observers are. Any number of observers can subscribe to receive notifications.

Observer in the Java APIs

Here are some examples of the Observer pattern from the standard Java APIs:

  • The Observer pattern is supported by the Observer and Observable classes in the java.util package. However, these classes are not used very often in real world Java programming because the Observable class must be subclassed. Java only supports single inheritance, so this becomes a problem if the subject class already extends another class.
  • Observable and Observer have been deprecated in Java 9 because their event model is fairly limited. The order of notifications delivered by Observable is unspecified, and state changes do not correspond one-to-one with the notifications. The update() method of the Observer is passed an Observable object. If we need to know what specific object it is, we have to implement our own code using instanceof checking and type casting.
  • The better approach to implementing the Observer pattern is with events and listeners. A custom event can extend the java.util.EventObject class. The java.util.EventListener tagging interface is used to define a listener class. Over 330 interfaces and classes in Java SE implement this interface.
  • The JEE Servlet API uses listeners to be advised of changes to the ServletContext, the ServletRequest and the HttpSession.
  • JSF (JavaServer Faces) uses it in the javax.faces.event.PhaseListener.
  • The Spring ApplicationContext container implements the ApplicationEventPublisher interface which allows events to be published with the publishEvent() methods.

State Pattern: Example Code

Back in our first person shooter game, we’ve decided that when players are stuck in a dangerous situation, they could call for reinforcements. Obviously the reinforcements won’t arrive instantly; they may be helping another player, or be far away on the game map.

The player would just as obviously like to know when the reinforcements are on the way. We can just let the player keep on radioing in to headquarters to find out when help is on the way, which will take time and energy, and distract the player from defending themselves from the zombie hordes or werewolf packs.

A better solution would be to allow the player to register a call with HQ and be advised when to expect the reinforcements. This is where the Observer design pattern comes into its own.

The player would be the observer. Headquarters would have a number of observers, who they would notify whenever reinforcements are on their way.

We won’t use the Observer and Observable classes in this example. We’ll take the alternative approach of using events and listeners.

Let’s first define an event class for the reinforcements:

public class CavalryIsOnTheWayEvent extends java.util.EventObject {

    private String message;

    public CavalryIsOnTheWayEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

The superclass EventObject provides a getSource() method so that listeners will be able to get a reference to the object that sent the event. It’s not particularly important to know here because there is only one headquarters, but in later versions of the game, the reinforcements may be sent from other areas.

Next we need to create a listener interface that will be implemented by the player. THis interface will extend the java.util.EventListener interface:

public interface CavalryListener extends java.util.EventListener {
    public void helpIsComing(CavalryIsOnTheWayEvent event);
}

The HeadQuarters class must handle listener registration and notifications internally. The Observable class handle registration and notifications, but it needs to be subclassed. This would be a problem if the HeadQuarters class extended another class, which could easily be the case as we extend the game.

public class HeadQuarters {

    private List listeners;

    public HeadQuarters() {
        listeners = new ArrayList<>();
        // other constructor code
    }

    public void addCavalryListener(CavalryListener listener) {
        listeners.add(listener);
    }

    public void removeCavalryListener(CavalryListener listener) {
        listeners.remove(listener);
    }

    public void sendingOutReinforcements() {
        fireHelpIsComing("The cavalry is 10 minutes away!");
    }

    protected void fireHelpIsComing(String message) {
        CavalryIsOnTheWayEvent event;
        event = new CavalryIsOnTheWayEvent(this, message);
        for (CavalryListener listener : listeners) {
            listener.helpIsComing(event);
        }
    }
}

The Player object is the listener/observer and needs to implement the CavalryListener interface:

public class Player implements CavalryListener {
    // other code

    public void helpIsComing(CavalryIsOnTheWayEvent event) {
        System.out.println ("Help has been sent from " + event.getSource() );
        System.out.println ("The message was " + event.getMessage() );
    }
}

This is how the code works in the client program:

HeadQuarters hq = new HeadQuarters();
Player player   = new Player();
hq.addCavalryListener(player);
hq.sendingOutReinforcements(30);
hq.sendingOutReinforcements(20);
hq.sendingOutReinforcements(10);

Related Patterns

The Observer pattern is used in the Model-View-Controller architecture. The Model is the Subject; the View is the Observer.

What’s next?

In the weeks ahead, we’ll continue examining some of the more useful design patterns. Stay tuned!

As always, please share your comments and questions.

You’ve probably heard of a functional interface before, often in the same breath as lambdas. What are functional interfaces, and why are they used with lambdas?

Lambdas and functional interfaces go hand in hand in Java.

A functional interface is simply an interface that has a single abstract method. Before Java 8, they were referred to as SAM interfaces.

Why are these interfaces so important that they have their own term? Two reasons:

  1. Good design.
    The “I” in the SOLID design principles refers to the Interface Segregation Principle. This states that many small interfaces are better than one large general purpose interface. Clients shouldn’t be forced to implement interfaces they don’t use. So functional interfaces are the ultimate small interface.
  2. Lambdas.
    The only way the compiler can infer which method you’re trying to implement with a lambda expression is that there is only a single method that you can implement.

Quick recap

Let’s revisit the Comparator example from the previous post.

Using the anonymous inner class code, it’s obvious what you’re doing: you’re implementing the compare() method:

// use an anonymous inner class to create a Comparator object
TreeSet ts = new TreeSet<>(
        new Comparator() {
            @Override
            public int compare(Employee e1, Employee e2) {
                return e1.getAge() - e2.getAge();
            }
        }
    );

But when you’re using a lambda expression, what can the compiler infer? The only way it can work out what you’re trying to do, is if you’re only allowed to implement a single method.

// use an lambda to create a Comparator object

TreeSet ts = new TreeSet<>(
         (Employee e1, Employee e2) -> { 
                  return e1.getAge() - e2.getAge(); }
    );

The Comparator interface is a functional interface, with the compare() method being the only abstract method.

@FunctionalInterface annotation

The @FunctionalInterface annotation marks the interface as a functional interface. It forces the compiler to check that there is only one abstract method.

At first this seems unnecessary. Interfaces are usually very small Java classes and it should be easy to just see what’s in the interface. But from Java 8, we’re allowed to have implemented methods in an interface. These are static and default methods. If there are a lot of methods, it is difficult for a programmer to check that they only have one abstract method, or haven’t forgotten to implement a method appropriately.

For example:

@FunctionalInterface
public interface MyInterface {
    public void foo(); // single abstract method

    // default instance method - can be overridden if needed
    public default void bar() {
        // appropriate code
    }

    // static class method - called as MyInterface.baz() 
    public static void baz() {
       // appropriate code
    }
}

Functional interfaces as targets for lambda expressions

As a general rule, you can’t reuse lambda expressions. If you pass a lambda expression to a method, you would usually copy-and-paste it if you wanted to use it again.

Functional interfaces to the rescue! Variables of functional interface types can be used as targets for lambda expressions. This means that you can assign a lambda expression to a variable, as long as that variable’s type is a functional interface.

Revisiting the Comparator example, we can reuse the lambda expression easily if we assign it to a functional interface type:

Comparator cmp1 = (Employee e1, Employee e2) -> { 
                     return e1.getAge() - e2.getAge(); }

Comparator cmp2 = (e1, e2) -> { 
                     return e1.getAge() - e2.getAge(); }

Comparator cmp3 = (e1, e2) -> 
                     e1.getAge() - e2.getAge();

TreeSet ts = new TreeSet<>(cmp3);

I’ll cover the default and static methods of Comparator in a later post.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.