Applying the Observer to the Case Study

My approach is to look in the problem for clues as to what is varying. Then, I attempt to encapsulate the variation. In the current case, I find:

  • Different kinds of objects— There is a list of objects that need to be notified of a change in state. These objects tend to belong to different classes.

  • Different interfaces— Since they belong to different classes, they tend to have different interfaces.

First, I must identify all of the objects that want to be notified. I will call these the observers since they are waiting for an event to occur.

I want all of the observers to have the same interface. If they do not have the same interface, then I would have to modify the subject—that is, the object that is triggering the event (for example, Customer), to handle each type of observer.

By having all of the observers be of the same type, the subject can easily notify all of them. To get all of the observers to be of the same type,

  • In Java, I would probably implement this with an interface (either for flexibility or out of necessity).

  • In C++, I would use single inheritance or multiple inheritance, as required.

In most situations, I want the observers to be responsible for knowing what they are to watch for and I want the subject to be free from knowing which observers depend on it. To do this, I need to have a way for the observers to register themselves with the subject. Since all of the observers are of the same type, I must add two methods to the subject:

  • attach(Observer) adds the given Observer to its list of observers

  • detach(Observer) removes the given Observer from its list of observers

Now that the Subject has its Observers registered, it is a simple matter for the Subject to notify the Observers when the event occurs. To do this, each Observer implements a method called update. The Subject implements a notify method that goes through its list of Observers and calls this update method for each of them. The update method should contains the code to handle the event.

But notifying each observer is not enough. An observer may need more information about the event beyond the simple fact that it has occurred. Therefore, I must also add method(s) to the subject that allow the observers to get whatever information they need. Figure 17-2 shows this solution.

Figure 17-2. Implementing Customer with Observer.


In Figure 17-2, the classes relate to each other as follows:

  1. The Observers attach themselves to the Customer class when they are instantiated. If the Observers need more information from the subject (Customer), the update method must be passed a reference to the calling object.

  2. When a new Customer is added, the notify method calls these Observers.

Each Observer calls getState for information on the newly added Customer to see what it needs to do. Note: Typically, there would be several methods to get the needed information.

Note in this case, we use static methods for attach and detach because observers want to be notified for all new Customers. When notified, they are passed the reference to the Customer created.

Example 17-1 shows some of the code required to implement this.

This approach allows me to add new Observers without affecting any existing classes. It also keeps everything loosely coupled. This organization works if I have kept all of the objects responsible for themselves.

How well does this work if I get a new requirement? For example, what if I need to send a letter with coupons to customers located within 20 miles of one of the company's “brick and mortar” stores.

Example 17-1. Java Code Frament: Observer Implemented
// Note: Do not actually use the name Observer
// as that is a Java class in java.util

class Customer {
  static private Vector myObs;
  static {
    myObs= new Vector();
  }
  public static void attach(Observer o){
    myObs.addElement(o);
  }
  public static void detach(Observer o){
    myObs.remove(o);
  }
  public String getState () {
    // have other methods that will give the
    // required information
  }

  public void notifyObs () {
    for (Enumeration e =
      myObs.elements();
      e.hasMoreElements() ;) {
       ((Observer) e).update(this);
    }
  }
}


abstract class Observer {
  public Observer () {
    Customer.attach( this);
  }
  abstract public void
    update(Customer myCust);
}

class AddrVerification extends Observer {
  public AddrVerification () {
    super();
  }
  public void update (
    Customer myCust) {
    // do Address verification stuff here
    // can get more information about customer
    // in question by using myCust
  }
}

class WelcomeLetter extends Observer {
  public WelcomeLetter () {
    super();
  }
  public void update (Customer myCust) {
    // do Welcome Letter stuff
    // here can get more
    // information about customer
    // in question by using myCust
  }
}

To accomplish this, I would simply add a new observer that sends the coupon. It only does this for new customers living within the specified distance. I could name this observer BrickAndMortar and make it an observer to the Customer class. Figure 17-3 shows this solution.

Figure 17-3. Adding the BrickAndMortar observer.


Sometimes, a class that will become an Observer may already exist. In this case, I may not want to modify it. If so, I can easily adapt it with the Adapter pattern. Figure 17-4 shows an example of this.

Figure 17-4. Implementing Observer with Adapters.


The Observable Class: A Note to Java developers.

The Observer pattern is so useful that Java contains an implementation of it in its packages. The Observable class and the Observer interface make up the pattern. The Observable class plays the role of the Subject in the Gang of Four's description of the pattern. Instead of the methods attach, detach, and notify, Java uses addObserver, deleteObserver, and notifyObservers, respectively (Java also uses update). Java also gives you a few more methods to make life easier.[1]


[1] See http://java.sun.com/j2se/1.3/docs/api/index.html for information on the Java API for Observer and Observable.

The Observer Pattern: Key Features

Intent Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Problem You need to notify a varying list of objects that an event has occurred.
Solution Observers delegate the responsibility for monitoring for an event to a central object: the Subject.
Participants and Collaborators The Subject knows its Observers because the Observers register with it. The Subject must notify the Observers when the event in question occurs. The Observers are responsible both for registering with the Subject and for getting the information from the Subject when notified.
Consequences Subjects may tell Observers about events they do not need to know if some Observers are interested in only a subset of events (see "Field Notes: Using the Observer Pattern" on page 274). Extra communication may be required if Subjects notify Observers which then go back and request additional information.
Implementation
  • Have objects (Observers) that want to know when an event happens attach themselves to another object (Subject) that is watching for the event to occur or that triggers the event itself.

  • When the event occurs, the Subject tells the Observers that it has occurred.

  • The Adapter pattern is sometimes needed to be able to implement the Observer interface for all of the Observer-type objects.

GoF Reference Pages 293–303.

Figure 17-5. Standard, simplified view of the Observer pattern.



..................Content has been hidden....................

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