April 17, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Working with Design Patterns: Observer, Page 2

  • August 17, 2007
  • By Jeff Langr
  • Send Email »
  • More Articles »

Listing 2: java.util.Observer.

public interface Observer {
    void update(Observable o, Object arg);
}

Clients wanting to observe something can call the addObserver method against an Observable subclass instance. Making this call effectively registers the interested client with the Observable object. The argument to addObserver must be of the interface type Observer. The most succinct way of accomplishing things is to use an anonymous inner class. Or, the client object itself could implement the Observer interface.

Here, my client code implements the update method as part of an anonymous inner class:

FaxServer server = new FaxServer(dialer, transmitter);
server.addObserver(new Observer() {
   public void update(Observable o, Object arg) {
      FaxServer server = (FaxServer)o;
      System.out.println("Status: " + server.status());
   }});

Calls to the update method come along with two arguments: a reference to the Observable object, plus an optional Object instance that can be used for passing pertinent information. In my implementation, I cast the Observable reference to a FaxServer reference, and then ask for its status string.

Listing 3 provides the modified FaxServer code. My changes are shown in bold. Instead of System.out statements, I call a setStatus method. This method changes a status instance variable to contain text representing the new state. The setStatus method then calls setChanged, an Observable method that indicates a relevant change was made. Without this call, no notifications can go out. Finally, code in the setStatus method calls the Observable method notifyObservers, which ultimately triggers the call of update methods defined on registered Observer objects.

Listing 3: The modified FaxServer class.

import java.util.*;
import java.util.concurrent.*;

public class FaxServer extends Observable {
   private DelayQueue<FaxTransmission> queue =
      new DelayQueue<FaxTransmission>();
   private Dialer dialer;
   private Transmitter transmitter;
   private String status;

   public FaxServer(Dialer dialer, Transmitter transmitter) {
      this.dialer = dialer;
      this.transmitter = transmitter;
   }

   public void start() {
      new Thread(new Runnable() {
         public void run() {
            while (true) {
               try {
                  transmit(queue.take());
               }
               catch (InterruptedException e) {
               }
            }
         }
      }).start();
   }

   private void transmit(FaxTransmission transmission) {
      if (dialer.connect(transmission.getFax().to())) {
         setStatus(String.format("sending %s.", transmission));
         transmitter.send(transmission.getFax());
         setStatus("completed");
         notifyObservers(this);
      }
      else {
         setStatus(
            String.format("busy, queuing %s for resend%n",
                          transmission));
         transmission.setToResend();
         queue.add(transmission);
      }
   }

   public void send(Fax fax) {
      setStatus(String.format("queuing %s%n", fax));
      queue.add(new FaxTransmission(fax));
   }

   public String status() {
      return status;
   }

   private void setStatus(String status) {
      this.status = status;
      setChanged();
      notifyObservers();
   }
}

The addObserver defined on the Observable method may be called by multiple interested clients. Observable also provides a deleteObserver method. A note of caution: Because Observable objects can hold references to many interested clients, it's possible for me to introduce memory leaks if I'm not careful about relinquishing observation.

My implementation of the fax server is probably still not ideal. Embedded status strings aren't a good idea if I want to ship my server to international destinations. I'd probably want to notify the client of a status enum, or maybe just a message ID.

Also, nothing prevents me from implementing my own implementation of the observer pattern. It's nice to have built-in functionality, but somehow it makes more sense to just roll my own. For the fax server, for example, I might have provided an interface named FaxObserver, defining within it various status callbacks:

interface FaxObserver {
   void sendInitiated();
   void sendCompleted();
   void queueing();
   void resending();
}




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel