1.8 The Command Pattern
Keywords: current

Next: 1.8.1 Static Members of Up: 1. From C++ to Previous: 1.7.3 Interface Types

#
1.8 The Command Pattern

In a finger exercise in Section 1.4.3, we extended the `DeptDirectory` program by writing a method `findPhone(String name)` to look up a person's phone number. We implemented `findPhone` in exactly the same way as `findAddress`, replicating method code. A better strategy would be to implement a method

> `Entry findEntry(String name)`

that returns the `Entry` matching a given `name`, and then to define both `findPhone` and `findAddress` in terms of `findEntry`.

In this section, we will explore a far more general technique for eliminating code replication called the command pattern. To accommodate returning different `Entry` fields, we will define a method

> `String findField(Operation f, String name)`

that takes an `Operation` object as an extra argument specifying which field to return. This approach implements the well-known ``code factoring'' process described above; repeated code patterns are abstracted into methods that take parameters that ``customize'' the code appropriately. In many cases, these parameters are ``command'' objects representing methods.

Code factoring involving methods as parameters cannot be directly implemented in Java because methods are not values that can be passed as arguments. Some object oriented languages such as SmallTalk and Self classify methods as data values, permitting code factoring to be implemented directly. Fortunately, it is not difficult to get around this restriction by explicitly representing methods as objects. All we have to do is introduce an appropriate abstract class `Operation` containing a single abstract method `execute( ... )` and define a separate concrete subclass of `Operation` for each method that we want to pass as an argument. Each concrete subclass defines the abstract method `execute` appropriately. In the general case, the `Operation` subclasses may contain fields that correspond to the free variables appearing in procedural arguments in functional languages. These free variables must be bound when the `Operation` is constructed, exactly as they are in a language supporting procedures as data values.

In the object-oriented design literature, this technique is called the command pattern in homage to the dominant role that imperative operations have played in object-oriented computation. Here we are using this pattern in a purely functional fashion.

To illustrate the command pattern, let us continue our `DeptDirectory` example. If we independently write `findPhone` and `findAddress`, they differ only in the field name used in the `return` expression.

    class Empty extends DeptDirectory {

      ...

      String findAddress(String name) {
        return null;
      }
      String findPhone(String name) {
        return null;
      }
    }

    class Cons extends DeptDirectory {

      ...

      String findAddress(String name) {
        if (name.equals(first.name))
          return first.getAddress();
        else return rest.findAddress(name);
      }
      String findPhone(String name) {
        if (name.equals(first.name))
          return first.getPhone();
        else return rest.findPhone(name);
      }
    }

We can ``abstract out'' this difference by writing a single `findField` method embodying the common code in the methods `findPhone` and `findAddress`. To accommodate differing choices for the returned `Entry` field, the method takes an `Operation` that performs the appropriate field extraction on the `Entry`. The following code includes a new mechanism for defining concrete subclasses, called anonymous classes, that we have not discussed before. We will explain anonymous classes in detail below. In this example, anonymous classes are used to generate instances of new subclasses of the interface `OperationI`; the static fields `address` and `phone` are bound to objects of type `Operation` that define the `execute` method as the method extracting the `address` and `phone` fields, respectively, of an `Entry`.

    interface OperationI {
      String execute(Entry e);  // implicity public and abstract

    }

    abstract class DeptDirectory {
      ...
      abstract String findField(OperationI c, String name);
      String findAddress(String name) {
        return findField(opddress, name);
      }
      String findPhone(String name) {
        return findField(opPhone, name);

      static OperationI opAddress = new OperationI() {
        // ANONYMOUS class
        public String execute(Entry e) { return e.getAddress(); }
      }
      static OperationI opPhone = new OperationI() {
        // ANONYMOUS class
        public String execute(Entry e) { return e.getPhone(); }
      }
    }

    class Empty extends DeptDirectory {
      ...
      String findField(OperationI c, String name) {
        return null;
      }
    }

    class Cons extends DeptDirectory {
      ...
      String findField(OperationI c, String name) {
        if (name.equals(first.name)) return c.execute(first);
        else return rest.findField(c,name);
      }
    }

Each brace construction

      {  // ANON CLASS
        public String execute(Entry e) { return e. ...; }
      }

following a `new OperationI()` expression above defines a unique instance of a new anonymous (unnamed) class implementing the interface `OperationI`. In Java, anonymous classes are simply an abbreviation mechanism. The `OperationI` class could have been written without anonymous classes as follows:

    interface OperationI {
      String execute(Entry e);
      }
    }
    class AddressOperation implements OperationI {
      public String execute(Entry e) {
        return e.getOffice();
      }
    }
    class PhoneOperation implements OperationI {
      public String execute(Entry e) {
        return e.getPhone();
      }
    }
    abstract class DeptDirectory {
      ...
      static OperationI opAddress = new AddressOperation();
      static OperationI opPhone = new PhoneOperation();
    }

at the cost of introducing the new class names `AddressOperation` and `PhoneOperation`.

In general, a single instance of a new class extending class (implementing interface) C can be created using the notation:

> `new C(...) { ...` members `...}`

where `C(...)` specifies what superclass initialization should be performed on the instance. If C is an interface, then the argument list in `C(...)` must be empty. No constructors can appear in the list of members because the class is nameless and cannot be instantiated again. Any required initialization of fields inside the instance can be specified directly in the code defining the class.

If we ignore the ugly notation, an anonymous class extending the abstract class `OperationI` has a direct analog in functional languages, namely an anonymous function or `lambda`-expression. In any situation in a functional language where it is appropriate to use a `lambda`-expression, you can use an anonymous class in Java! The failure to make such an identification is the single most glaring failure of most expositions on Java.

If an anonymous class appears inside a dynamic method, it can contain references to the fields of the enclosing class instance--akin to the free variables that can appear in `lambda`-expressions. The only complication is the treatment of the variable `this`. Since an anonymous class defines an instance of a new class, the variable `this` inside an anonymous class refers to the new class instance. It does not refer to the enclosing class instance. To refer to the ``entire'' enclosing class instance, Java uses the notation `.this` where is the name of the enclosing class.

Exercises:

1. Add a `map` method to the `IntList` class that takes an `OperationI` and applies it to each element of `this` to produce a new `IntList` with exactly the same number of elements as `this`.
2. Assume that a vector

   is represented by the list

   where the coefficient's are objects of type `Double`. Add a method

   > `double norm()`

   to `IntList` computes the norm by `this.v` by squaring the elements, adding the squares together and taking the square-root of the sum. You can compute the vector of squares using `map` and the define a method `double sum()` to compute the sum.
3. Assume that a polynomial

   is represented by the list

   where the coefficient's are objects of type `Double`. Write a method

   > `double eval(IntList p, Double x)`

   to evaluate the polynomial at coordinate x. Use Horner' rule asserting that

   Remember to use the structural design pattern for processing lists (and by association polynomials as we have represented them).

Subsections

- 1.8.1 Static Members of Classes
- 1.8.2 Complete Java Programs
  - 1.8.2.1 A Complete Java Program
- 1.8.3 When to Use Static Methods

Next: 1.8.1 Static Members of Up: 1. From C++ to Previous: 1.7.3 Interface Types