January 27, 2021
Hot Topics:

Working with Design Patterns: Observer

  • By Jeff Langr
  • Send Email »
  • More Articles »

In an earlier article on threading, I provided an implementation for a fax server (see Listing 1 for code implemented in the core classes). Within the server code, I directly embedded System.out.println statements. Although it's an acceptable technique for demonstration purposes, I rarely want to intermingle my server code and display output.

Listing 1: Fax server and client.

// Fax.java:
package waitperiod;

import java.util.concurrent.*;

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

   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 {
               catch (InterruptedException e) {

   private void transmit(FaxTransmission transmission) {
      if (dialer.connect(transmission.getFax().to())) {
         System.out.printf("sending %s.", transmission);
      else {
         System.out.printf("busy, queuing %s for resend%n",

   public void send(Fax fax) {
      System.out.printf("queuing %s%n", fax);
      queue.add(new FaxTransmission(fax));

// Client.java:
import java.util.*;
import util.*;

public class Client {
   public static void main(String[] args) {
      Fax fax1 = new Fax("1", "5555", "some message 1");
      Fax fax2 = new Fax("2", "6666", "some message 2");
      Fax fax3 = new Fax("3", "7777", "some message 3");
      Fax fax4 = new Fax("4", "8888", "some message 4");

      Dialer dialer = new Dialer() {
         private Random random = new Random();
         public boolean connect(String number) {
            return random.nextInt(5) == 0;

      Transmitter transmitter = new Transmitter()  {
         public void send(Fax fax) {
            for (int i = 0; i < 10; i++) {

      FaxServer server = new FaxServer(dialer, transmitter);

Separating user interface output from logic is almost always a good idea. It sets the stage for cheaper and safer maintenance in the future, when, for example, I want to change the fax server from a console application to something that interacts with a nice LCD output panel. It's also easier to write tests against single-purpose code. In contrast, having code that combines the two purposes of presentation and fax management is considerably more difficult to test.

Generally, I want the clients exercising my fax server to be the ones driving where the output should go and how it should be formatted. A simple solution would be to have the client object pass a reference to itself to the FaxServer. The FaxServer would call back to the client when anything of interest occurred.

But, such a simple solution is less than ideal. The client is already cognizant of the FaxServer, which is necessary. Now, the FaxServer would need to know the type of the client. Changes to the client could potentially ripple into the FaxServer. This sort of two-way dependency is, in most cases, a bad design choice.

The observer design pattern provides a simple solution: Instead of passing a client reference to the fax server, the client passes an abstraction of itself. It defines itself as an "observer" by implementing an interface (java.util.Observer), and then passes the interface reference to the fax server. The fax server knows only that it's interacting with an Observer instance, not a ConsoleClient or a FancyLcdPanelClient.

Use of observer is so common that Java provides a built-in implementation of the pattern. Java supplies the java.util.Observer interface, which defines the single method update (see Listing 2). It also supplies the java.util.Observable class. A class defines itself as the target of observation by extending Observable.

Page 1 of 3

This article was originally published on August 17, 2007

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date