According to Head First Design Patterns book, this is the definition of 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.
Sounds familiar? Have you ever worked with Swing? Looks like the event handling mechanism is using the Observer Pattern. Let’s think about it, suppose you have a JButton and you want other objects to be notified when the button is pressed… have you done that? sure! The other objects are not asking all the time to the button whether it is pressed or not, they only wait for a notification from the button. Swing does it using the java.awt.event.ActionListener, but in essence it is using the Observer Pattern, even if we are not using interfaces like java.util.Observer or classes like java.util.Observable…
Now, talking about observers and observables, this two exist since JDK 1.0 and you can use them to implement the Observer Pattern in your applications. Let’s see the how to do it:
The objects you want to be waiting for notifications are called Observers, they implement the interface java.util.Observer. This interface defines only one method: +update(Observable,Object):void which is called whenever the observed object is changed. The first parameter, an Observable, is the object that changed. The second parameter may be used as follows:
- If using PUSH notifications, the Object parameter contains the information needed by the observers about the change.
- If using PULL notifications, the Object parameter is null and you should use the Observable parameter in order to extract the information needed.
When to PUSH or PULL? It’s up to your implementation. The Object you want to be observed is called the Observable and it has to subclass the java.util.Observable class. Yes, subclass. That’s the dark side of the built-in implementation of the Observer Pattern in Java, sometimes you simply can’t subclass, we’ll talk about this in a minute… Once subclassed, you will inherit the following methods, among others:
- +addObserver(Observer):void which adds the Observer passed in as parameter to the set of observers.
- +deleteObserver(Observer):void which deletes the Observer passed in as parameter from the set of observers.
- setChanged():void which marks the Observable as having been changed. This method is protected, so you can only call it if you subclass the java.util.Observable class. Call it before notifying your observers.
- +notifyObservers():void which notifies the registered observers using PULL. It means that when the +update(Observable,Object):void is invoked on the Observer, the Object parameter will be null.
- +notifyObservers(Object):void which notifies the registered observers using PUSH. It means that when the +update(Observable,Object):void is invoked on the Observer, the Object parameter will be the same parameter passed in the +notifyObservers(Object):void .
So, what happens if the class you want to be the Observable is already subclassing another class? Well, then you have to write your own Observer Pattern implementation because you can’t use the one built-in Java. The following diagram shows you the basic concepts of the Observer Pattern, so you can built your own implementation:
One last thing, remember the most important OO Principle of all: Always use the simplest solution that meets your needs, even if it doesn’t include a pattern.
Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code
Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!
To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.