Chapter 2. The Observer Pattern: Keeping your Objects in the know

image with no caption

Don’t miss out when something interesting happens! We’ve got a pattern that keeps your objects in the know when something they might care about happens. Objects can even decide at runtime whether they want to be kept informed. The Observer Pattern is one of the most heavily used patterns in the JDK, and it’s incredibly useful. Before we’re done, we’ll also look at one-to-many relationships and loose coupling (yeah, that’s right, we said coupling). With Observer, you’ll be the life of the Patterns Party.

Congratulations!

Your team has just won the contract to build Weather-O-Rama, Inc.’s next-generation, Internet-based Weather Monitoring Station.

Statement of Work

Congratulations on being selected to build our next-generation, Internet-based Weather Monitoring Station!

The weather station will be based on our patent pending WeatherData object, which tracks current weather conditions (temperature, humidity, and barometric pressure). We’d like you to create an application that initially provides three display elements: current conditions, weather statistics, and a simple forecast, all updated in real time as the WeatherData object acquires the most recent measurements.

Further, this is an expandable weather station. Weather-ORama wants to release an API so that other developers can write their own weather displays and plug them right in. We’d like for you to supply that API!

Weather-O-Rama thinks we have a great business model: once the customers are hooked, we intend to charge them for each display they use. Now for the best part: we are going to pay you in stock options.

We look forward to seeing your design and alpha application.

Sincerely,

Johnny Hurricane, CEO

P.S. We are overnighting the WeatherData source files to you.

The Weather Monitoring application overview

The three players in the system are the weather station (the physical device that acquires the actual weather data), the WeatherData object (that tracks the data coming from the Weather Station and updates the displays), and the display that shows users the current weather conditions.

image with no caption

The WeatherData object knows how to talk to the physical Weather Station, to get updated data. The WeatherData object then updates its displays for the three different display elements: Current Conditions (shows temperature, humidity, and pressure), Weather Statistics, and a simple forecast.

Our job, if we choose to accept it, is to create an app that uses the WeatherData object to update three displays for current conditions, weather stats, and a forecast.

Unpacking the WeatherData class

As promised, the next morning the WeatherData source files arrive. When we peek inside the code, things look pretty straightforward:

image with no caption
image with no caption

Our job is to implement measurementsChanged() so that it updates the three displays for current conditions, weather stats, and forecast.

What do we know so far?

image with no caption

The spec from Weather-O-Rama wasn’t all that clear, but we have to figure out what we need to do. So, what do we know so far?

The WeatherData class has getter methods for three measurement values: temperature, humidity, and barometric pressure.

getTemperature()
getHumidity()
getPressure()

The measurementsChanged() method is called any time new weather measurement data is available. (We don’t know or care how this method is called; we just know that it is.)

measurementsChanged()

We need to implement three display elements that use the weather data: a current conditions display, a statistics display, and a forecast display. These displays must be updated each time WeatherData has new measurements.

The system must be expandable—other developers can create new custom display elements and users can add or remove as many display elements as they want to the application. Currently, we know about only the initial three display types (current conditions, statistics, and forecast).

Taking a first, misguided SWAG at the Weather Station

Here’s a first implementation possibility—we’ll take the hint from the Weather-O-Rama developers and add our code to the measurementsChanged() method:

image with no caption

Definition of SWAG: Scientific Wild A** Guess

What’s wrong with our implementation?

Think back to all those Chapter 1 concepts and principles...

image with no caption
image with no caption

We’ll take a look at Observer, then come back and figure out how to apply it to the Weather Monitoring app.

Meet the Observer Pattern

You know how newspaper or magazine subscriptions work:

  • ① A newspaper publisher goes into business and begins publishing newspapers.

  • ② You subscribe to a particular publisher, and every time there’s a new edition it gets delivered to you. As long as you remain a subscriber, you get new newspapers.

  • ③ You unsubscribe when you don’t want papers anymore, and they stop being delivered.

  • ④ While the publisher remains in business, people, hotels, airlines, and other businesses constantly subscribe and unsubscribe to the newspaper.

image with no caption

Publishers + Subscribers = Observer Pattern

If you understand newspaper subscriptions, you pretty much understand the Observer Pattern, only we call the publisher the SUBJECT and the subscribers the OBSERVERS.

Let’s take a closer look:

image with no caption

A day in the life of the Observer Pattern

A Duck object comes along and tells the Subject that it wants to become an observer.

Duck really wants in on the action; those ints Subject is sending out whenever its state changes look pretty interesting...

The Duck object is now an official observer.

Duck is psyched... he’s on the list and is waiting with great anticipation for the next notification so he can get an int.

The Subject gets a new data value!

Now Duck and all the rest of the observers get a notification that the Subject has changed.

The Mouse object asks to be removed as an observer.

The Mouse object has been getting ints for ages and is tired of it, so it decides it’s time to stop being an observer.

Mouse is outta here!

The Subject acknowledges the Mouse’s request and removes it from the set of observers.

The Subject has another new int.

All the observers get another notification, except for the Mouse who is no longer included. Don’t tell anyone, but the Mouse secretly misses those ints... maybe it’ll ask to be an observer again some day.

Five-minute drama: a subject for observation

image with no caption

In today’s skit, two post-bubble software developers encounter a real live head hunter...

image with no caption
image with no caption

Two weeks later...

image with no caption

Jill’s loving life, and no longer an observer. She’s also enjoying the nice fat signing bonus that she got because the company didn’t have to pay a headhunter.

image with no caption

But what has become of our dear Lori? We hear she’s beating the headhunter at his own game. She’s not only still an observer, she’s got her own call list now, and she is notifying her own observers. Lori’s a subject and an observer all in one.

The Observer Pattern defined

When you’re trying to picture the Observer Pattern, a newspaper subscription service with its publisher and subscribers is a good way to visualize the pattern.

In the real world, however, you’ll typically see the Observer Pattern defined like this:

Note

The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

Let’s relate this definition to how we’ve been talking about the pattern:

image with no caption

The Observer Pattern defines a one-to-many relationship between a set of objects.

When the state of one object changes, all of its dependents are notified.

The subject and observers define the one-to-many relationship. The observers are dependent on the subject such that when the subject’s state changes, the observers get notified. Depending on the style of notification, the observer may also be updated with new values.

As you’ll discover, there are a few different ways to implement the Observer Pattern, but most revolve around a class design that includes Subject and Observer interfaces.

Let’s take a look...

The Observer Pattern defined: the class diagram

image with no caption

The power of Loose Coupling

When two objects are loosely coupled, they can interact, but have very little knowledge of each other.

The Observer Pattern provides an object design where subjects and observers are loosely coupled.

Why?

The only thing the subject knows about an observer is that it implements a certain interface (the Observer interface). It doesn’t need to know the concrete class of the observer, what it does, or anything else about it.

We can add new observers at any time. Because the only thing the subject depends on is a list of objects that implement the Observer interface, we can add new observers whenever we want. In fact, we can replace any observer at runtime with another observer and the subject will keep purring along. Likewise, we can remove observers at any time.

We never need to modify the subject to add new types of observers. Let’s say we have a new concrete class come along that needs to be an observer. We don’t need to make any changes to the subject to accommodate the new class type; all we have to do is implement the Observer interface in the new class and register as an observer. The subject doesn’t care; it will deliver notifications to any object that implements the Observer interface.

We can reuse subjects or observers independently of each other. If we have another use for a subject or an observer, we can easily reuse them because the two aren’t tightly coupled.

Changes to either the subject or an observer will not affect the other. Because the two are loosely coupled, we are free to make changes to either, as long as the objects still meet their obligations to implement the subject or observer interfaces.

Note

How many different kinds of change can you identify here?

Design Principle

Strive for loosely coupled designs between objects that interact.

Loosely coupled designs allow us to build flexible OO systems that can handle change because they minimize the interdependency between objects.

Cubicle conversation

Back to the Weather Station project. Your teammates have already started thinking through the problem...

image with no caption

Mary: Well, it helps to know we’re using the Observer Pattern.

Sue: Right... but how do we apply it?

Mary: Hmm. Let’s look at the definition again:

The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Mary: That actually makes some sense when you think about it. Our WeatherData class is the “one” and our “many” is the various display elements that use the weather measurements.

Sue: That’s right. The WeatherData class certainly has state... that’s the temperature, humidity, and barometric pressure, and those definitely change.

Mary: Yup, and when those measurements change, we have to notify all the display elements so they can do whatever it is they are going to do with the measurements.

Sue: Cool, I now think I see how the Observer Pattern can be applied to our Weather Station problem.

Mary: There are still a few things to consider that I’m not sure I understand yet.

Sue: Like what?

Mary: For one thing, how do we get the weather measurements to the display elements?

Sue: Well, looking back at the picture of the Observer Pattern, if we make the WeatherData object the subject, and the display elements the observers, then the displays will register themselves with the WeatherData object in order to get the information they want, right?

Mary: Yes... and once the Weather Station knows about a display element, then it can just call a method to tell it about the measurements.

Sue: We gotta remember that every display element can be different... so I think that’s where having a common interface comes in. Even though every component has a different type, they should all implement the same interface so that the WeatherData object will know how to send them the measurements.

Mary: I see what you mean. So every display will have, say, an update() method that WeatherData will call.

Sue: And update() is defined in a common interface that all the elements implement...

Designing the Weather Station

How does this diagram compare with yours?

image with no caption

Implementing the Weather Station

We’re going to start our implementation using the class diagram and following Mary and Sue’s lead (from a few pages back). You’ll see later in this chapter that Java provides some built-in support for the Observer Pattern, however, we’re going to get our hands dirty and roll our own for now. While in some cases you can make use of Java’s built-in support, in a lot of cases it’s more flexible to build your own (and it’s not all that hard). So, let’s get started with the interfaces:

image with no caption

Brain Power

Mary and Sue thought that passing the measurements directly to the observers was the most straightforward method of updating state. Do you think this is wise? Hint: is this an area of the application that might change in the future? If it did change, would the change be well encapsulated, or would it require changes in many parts of the code?

Can you think of other ways to approach the problem of passing the updated state to the observers?

Don’t worry; we’ll come back to this design decision after we finish the initial implementation.

Implementing the Subject interface in WeatherData

REMEMBER: we don’t provide import and package statements in the code listings. Get the complete source code from http://wickedlysmart.com/head-first-design-patterns/.

Remember our first attempt at implementing the WeatherData class at the beginning of the chapter? You might want to refresh your memory. Now it’s time to go back and do things with the Observer Pattern in mind...

image with no caption

Now, let’s build those display elements

Now that we’ve got our WeatherData class straightened out, it’s time to build the Display Elements. Weather-O-Rama ordered three: the current conditions display, the statistics display, and the forecast display. Let’s take a look at the current conditions display; once you have a good feel for this display element, check out the statistics and forecast displays in the code directory. You’ll see they are very similar.

image with no caption

Power up the Weather Station

image with no caption
  • First, let’s create a test harness.

    The Weather Station is ready to go. All we need is some code to glue everything together. Here’s our first attempt. We’ll come back later in the book and make sure all the components are easily pluggable via a configuration file. For now here’s how it all works:

    image with no caption
  • ② Run the code and let the Observer Pattern do its magic.

    image with no caption

Using Java’s built-in Observer Pattern

So far we’ve rolled our own code for the Observer Pattern, but Java has built-in support in several of its APIs. The most general is the Observer interface and the Observable class in the java.util package. These are quite similar to our Subject and Observer interfaces, but give you a lot of functionality out of the box. You can also implement either a push or pull style of update to your observers, as you will see.

To get a high-level feel for java.util.Observer and java.util.Observable, check out this reworked OO design for the WeatherStation:

image with no caption
image with no caption

How Java’s built-in Observer Pattern works

The built-in Observer Pattern works a bit differently than the implementation that we used on the Weather Station. The most obvious difference is that WeatherData (our subject) now extends the Observable class and inherits the add, delete, and notify Observer methods (among a few others). Here’s how we use Java’s version:

For an Object to become an observer...

As usual, implement the Observer interface (this time the java.util.Observer interface) and call addObserver() on any Observable object. Likewise, to remove yourself as an observer, just call deleteObserver().

For the Observable to send notifications...

First of all you need to be Observable by extending the java.util.Observable superclass. From there it is a two-step process:

  • ① You first must call the setChanged() method to signify that the state has changed in your object.

  • ② Then, call one of two notifyObservers() methods:

    image with no caption

For an Observer to receive notifications...

It implements the update method, as before, but the signature of the method is a bit different:

If you want to “push” data to the observers, you can pass the data as a data object to the notifyObservers(arg) method. If not, then the Observer has to “pull” the data it wants from the Observable object passed to it. How? Let’s rework the Weather Station and you’ll see.

image with no caption

The setChanged() method is used to signify that the state has changed and that notifyObservers(), when it is called, should update its observers. If notifyObservers() is called without first calling setChanged(), the observers will NOT be notified. Let’s take a look behind the scenes of Observable to see how this works:

Why is this necessary? The setChanged() method is meant to give you more flexibility in how you update observers by allowing you to optimize the notifications. For example, in our Weather Station, imagine if our measurements were so sensitive that the temperature readings were constantly fluctuating by a few tenths of a degree. That might cause the WeatherData object to send out notifications constantly. Instead, we might want to send out notifications only if the temperature changes more than half a degree and we could call setChanged() only after that happened.

You might not use this functionality very often, but it’s there if you need it. In either case, you need to call setChanged() for notifications to work. If this functionality is something that is useful to you, you may also want to use the clearChanged() method, which sets the changed state back to false, and the hasChanged() method, which tells you the current state of the changed flag.

Reworking the Weather Station with the built-in support

First, let’s rework WeatherData to use java.util.Observable

image with no caption

Now, let’s rework the CurrentConditionsDisplay

image with no caption

Running the new code

Just to be sure, let’s run the new code...

image with no caption

Hmm, do you notice anything different? Look again...

You’ll see all the same calculations, but mysteriously, the order of the text output is different. Why might this happen? Think for a minute before reading on...

Never depend on order of evaluation of the Observer notifications

The java.util.Observable has implemented its notifyObservers() method such that the Observers are notified in a different order than our own implementation. Who’s right? Neither; we just chose to implement things in different ways.

What would be incorrect, however, is if we wrote our code to depend on a specific notification order. Why? Because if you need to change Observable/Observer implementations, the order of notification could change and your application would produce incorrect results. Now that’s definitely not what we’d consider loosely coupled.

image with no caption

The dark side of java.util.Observable

Yes, good catch. As you’ve noticed, Observable is a class, not an interface, and worse, it doesn’t even implement an interface. Unfortunately, the java.util.Observable implementation has a number of problems that limit its usefulness and reuse. That’s not to say it doesn’t provide some utility, but there are some large potholes to watch out for.

Observable is a class

You already know from our principles this is a bad idea, but what harm does it really cause?

First, because Observable is a class, you have to subclass it. That means you can’t add on the Observable behavior to an existing class that already extends another superclass. This limits its reuse potential (and isn’t that why we are using patterns in the first place?).

Second, because there isn’t an Observable interface, you can’t even create your own implementation that plays well with Java’s built-in Observer API. Nor do you have the option of swapping out the java.util implementation for another (say, a new, multithreaded implementation).

Observable protects crucial methods

If you look at the Observable API, the setChanged() method is protected. So what? Well, this means you can’t call setChanged() unless you’ve subclassed Observable. This means you can’t even create an instance of the Observable class and compose it with your own objects, you have to subclass. The design violates a second design principle here...favor composition over inheritance.

What to do?

Observable may serve your needs if you can extend java.util.Observable. On the other hand, you may need to roll your own implementation as we did at the beginning of the chapter. In either case, you know the Observer Pattern well and you’re in a good position to work with any API that makes use of the pattern.

Other places you’ll find the Observer Pattern in the JDK

The java.util implementation of Observer/Observable is not the only place you’ll find the Observer Pattern in the JDK; both JavaBeans and Swing also provide their own implementations of the pattern. At this point you understand enough about Observer to explore these APIs on your own; however, let’s do a quick, simple Swing example just for the fun of it.

Note

If you’re curious about the Observer Pattern in JavaBeans, check out the PropertyChangeListener interface.

A little background...

Let’s take a look at a simple part of the Swing API, the JButton. If you look under the hood at JButton’s superclass, AbstractButton, you’ll see that it has a lot of add/ remove listener methods. These methods allow you to add and remove observers, or, as they are called in Swing, listeners, to listen for various types of events that occur on the Swing component. For instance, an ActionListener lets you “listen in” on any types of actions that might occur on a button, like a button press. You’ll find various types of listeners all over the Swing API.

A little life-changing application

Okay, our application is pretty simple. You’ve got a button that says “Should I do it?” and when you click on that button the listeners (observers) get to answer the question in any way they want. We’re implementing two such listeners, called the AngelListener and the DevilListener. Here’s how the application behaves:

image with no caption

And the code...

This life-changing application requires very little code. All we need to do is create a JButton object, add it to a JFrame and set up our listeners. We’re going to use inner classes for the listeners, which is a common technique in Swing programming. If you aren’t up on inner classes or Swing, you might want to review the “Getting GUI” chapter of Head First Java.

image with no caption
image with no caption

Note

Lambda expressions were added in Java 8. If you aren’t familiar with them, don’t worry about it; you can continue using inner classes for your Swing observers.

Yes, you’re still using the Observer Pattern. By using a lambda expression rather than an inner class, you’re just skipping the step of creating an ActionListener object. With a lambda expression, you create a function object instead, and this function object is the observer. When you pass that function object to addActionListener(), Java ensures its signature matches actionPerformed(), the one method in the ActionListener interface.

Later, when the button is clicked, the button object notifies its observers—including the function objects created by the lambda expressions—that it’s been clicked, and calls each listener’s actionPerformed() method.

Let’s take a look at how you’d use lambda expressions as observers to simplify our previous code:

The updated code, using lambda expressions

image with no caption

Tools for your Design Toolbox

Welcome to the end of Chapter 2. You’ve added a few new things to your OO toolbox...

image with no caption
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.71.15