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 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.
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.
As promised, the next morning the WeatherData source files arrive. When we peek inside the code, things look pretty straightforward:
Our job is to implement measurementsChanged() so that it updates the three displays for current conditions, weather stats, and forecast.
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?
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:
Definition of SWAG: Scientific Wild A** Guess
Think back to all those Chapter 1 concepts and principles...
We’ll take a look at Observer, then come back and figure out how to apply it to the Weather Monitoring app.
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.
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:
In today’s skit, two post-bubble software developers encounter a real live head hunter...
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.
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.
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:
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:
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...
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.
Loosely coupled designs allow us to build flexible OO systems that can handle change because they minimize the interdependency between objects.
Back to the Weather Station project. Your teammates have already started thinking through the problem...
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...
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:
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.
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...
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.
① 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:
② Run the code and let the Observer Pattern do its magic.
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:
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:
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.
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.
First, let’s rework WeatherData to use java.util.Observable
Now, let’s rework the CurrentConditionsDisplay
Just to be sure, let’s run the new code...
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.
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.
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.
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:
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.
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:
Welcome to the end of Chapter 2. You’ve added a few new things to your OO toolbox...