SE450:  Lecture 4 
      (Structural Patterns)
    
 
 
        
          - 
            You have one and a half hours to take the exam.
          
- 
            If a question is unclear or
            ambiguous, write down your assumptions.
          
- 
            The exam is closed book and closed notes.
          
- 
            You may consult one letter-size page (front and back) of
            notes that you have prepared.
          
- 
            Write your answers on the exam.
            If I can not read your answer clearly, it will be marked as
            incorrect.
          
- 
            You will find some information on Java APIs, junit, and design
            patterns at the end of the exam.
          
- 
            When drawing UML class diagrams, follow these guidelines:
            
            -  Be specific (prefer aggregation and dependency to association, prefer
            composition to aggregation).
-  Show mutiplicities on aggregations and compositions.
- Be careful with arrowheads and with dashed/solid lines.
- Clearly distinguish classes and interfaces.
-  Clearly indicate static classes.
 
Here is a syllabus for the exam.
+ UML Object Diagrams
  - objects (fields with value)
  - relations
    * link
+ UML Sequence Diagrams
  - objects (lifetime) (also static classes)
  - method/constructor call (lifetime and arguments)
  - method/constructor return (value)
+ UML Class Diagrams
  - classes (fields and methods with type and visibility)
  - interfaces (methods with type and visibility)
  - big arrow relations (triangular arrowhead)
    * specialization
    * realization
  - small arrow relations
    * aggregation
    * composition
    * dependency
+ Simple Idioms and OO programming techniques (using java)
  - packages
  - interfaces
  - classes
  - constructors
  - delegation
  - inner classes
  - static versus object classes
  - immutable data classes
  - mutable data classes
  - data object methods (equals, hashCode, compareTo, ...)
  - collection classes
+ Patterns
  - static factory
  - builder
  - command
  - strategy
  - state
  - composite
        
       
 
        
          Interface: Primitive for describing the type
          or interface of an object.
        
        
          Class: Primitive for describing implementation of an
          object.
        
        
          Constructor: Primitive construct for building
          objects.
        
        
          Delegation: (Partial) responsibility for a message is
          given to another object.
        
        
        
          Subclassing: (Partial) responsibility for a message
          is given to a class other than the actual class of the
          object.
        [Not covered on midterm, except with respect to
        Object]
        
       
 
        
          Immutable Data Class: Unchanging data (eg, String).
        
        
          Mutable Data Class: Changing data (eg, an Employee
          class that contains salary information).
        
        
          Collection Class: A collection.  May be mutable or
          immutable.
        
       
 
        
          MVC lite: Separate IO from business logic.
        
       
 
        
          Static Class: A set of global variables and
          functions.
        
       
 
        
          Static Factory: a static class whose purpose is to
          generate instances of an interface (or interfaces).  The
          interface and factory are public, but the implementing
          classes are not.
        
        
          Builder: A mutable object used to build an immutable
          object.  Add pieces to the builder gradually, then convert
          to its immutable representation (eg, StringBuilder).
        
       
 
        
          Command: Encapsulate a function as an object.  The
          command can then be accessed from many places.  It may also
          support undo/redo.
        
        
          Strategy: Encapsulate variation into a separate
          object.  A method accesses the variation (strategy) by
          delegating to a field or parameter.
        
        
          State: Create the illusion that an object changes
          its actual type (using delegation to a field).  A nice way
          to eliminate case statments.
        
       
 
        
          Composite: Make collections of objects have the same
          interface as single objects.
        
       
 
        
       
 
        
          Allow collections to be treated the same as single objects.
        
        
          Define a typed tree.
        
        
          Here is an object diagram from the GOF:
        
         
        
          Here is a class diagram from the GOF:
        
         
       
 
        
          Here is an object diagram from the GOF:
        
         
        
          Here is a class diagram from the GOF:
        
         
       
 
        
          I will discuss
          these notes.
        
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 
 | package composite.one;
public class Main {
  public static void main(String[] args) {
    Expr one = new Const(1);
    Expr onePtwo = new Plus (new Const(1), new Const(2));
    Expr threeMfour = new Mult (new Const(3), new Const(4));
    Expr m = new Minus (onePtwo, threeMfour);
    Expr n = new Quot (m, new Const(5));
    System.out.println(n);
    System.out.println("Value: " + n.eval());
  }
}
 | 
 | 
 | 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 
 | package composite.one;
public interface Expr {
  int eval();
}
final class Const implements Expr {
  private final int v;
  public Const(int v) {
    this.v = v;
  }
  public int eval() {
    return v;
  }
  public String toString() {
    return Integer.toString(v);
  }
}
final class Plus implements Expr {
  private final Expr l;
  private final Expr r;
  public Plus(Expr l, Expr r) {
    if ((l == null) || (r == null)) {
      throw new IllegalArgumentException();
    }
    this.l = l;
    this.r = r;
  }
  public int eval() {
    return l.eval() + r.eval();
  }
  public String toString() {
    return l.toString() + " " + r.toString() + " +";
  }
}
final class Minus implements Expr {
  private final Expr l;
  private final Expr r;
  public Minus(Expr l, Expr r) {
    if ((l == null) || (r == null)) {
      throw new IllegalArgumentException();
    }
    this.l = l;
    this.r = r;
  }
  public int eval() {
    return l.eval() - r.eval();
  }
  public String toString() {
    return l.toString() + " " + r.toString() + " -";
  }
}
final class Mult implements Expr {
  private final Expr l;
  private final Expr r;
  public Mult(Expr l, Expr r) {
    if ((l == null) || (r == null)) {
      throw new IllegalArgumentException();
    }
    this.l = l;
    this.r = r;
  }
  public int eval() {
    return l.eval() * r.eval();
  }
  public String toString() {
    return l.toString() + " " + r.toString() + " *";
  }
}
final class Quot implements Expr {
  private final Expr l;
  private final Expr r;
  public Quot(Expr l, Expr r) {
    if ((l == null) || (r == null)) {
      throw new IllegalArgumentException();
    }
    this.l = l;
    this.r = r;
  }
  public int eval() {
    return l.eval() / r.eval();
  }
  public String toString() {
    return l.toString() + " " + r.toString() + " /";
  }
}
 | 
 | 
 | 
       
 
        
          - 
            Using a static factory
          
- 
            Refactor to strategy (binary operations all have same form)
          
- 
            nary ops.  What if PlusandMulttake any number of operands?  Need anaddmethod on the composite.
- 
            Using Builder for nary ops
          
- 
            Mutable Composites
            
              - 
                put addin interface
- 
                use two interfaces
              
 
 
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 
 | package composite.two;
public class Main {
  public static void main(String[] args) {
    Expr one = ExprFactory.newConst(1);
    Expr onePtwo = ExprFactory.newPlus
        (ExprFactory.newConst(1), ExprFactory.newConst(2));
    Expr threeMfour = ExprFactory.newMult
        (ExprFactory.newConst(3), ExprFactory.newConst(4));
    Expr m = ExprFactory.newMinus (onePtwo, threeMfour);
    Expr n = ExprFactory.newQuot (m, ExprFactory.newConst(5));
    System.out.println(n);
    System.out.println("Value: " + n.eval());
  }
}
 | 
 | 
 | 
         
|  | 
| | | 
0102
 03
 04
 
 | package composite.two;
public interface Expr {
  int eval();
}
 | 
 | 
 | 
         
|  | 
| | | 
001002
 003
 004
 005
 006
 007
 008
 009
 010
 011
 012
 013
 014
 015
 016
 017
 018
 019
 020
 021
 022
 023
 024
 025
 026
 027
 028
 029
 030
 031
 032
 033
 034
 035
 036
 037
 038
 039
 040
 041
 042
 043
 044
 045
 046
 047
 048
 049
 050
 051
 052
 053
 054
 055
 056
 057
 058
 059
 060
 061
 062
 063
 064
 065
 066
 067
 068
 069
 070
 071
 072
 073
 074
 075
 076
 077
 078
 079
 080
 081
 082
 083
 084
 085
 086
 087
 088
 089
 090
 091
 092
 093
 094
 095
 096
 097
 098
 099
 100
 101
 102
 103
 104
 
 | package composite.two;
public class ExprFactory {
  private ExprFactory() {}
  static public Expr newConst(int v) {
    return new Const(v);
  }
  static public Expr newPlus(Expr l, Expr r) {
    return new Plus(l, r);
  }
  static public Expr newMinus(Expr l, Expr r) {
    return new Minus(l, r);
  }
  static public Expr newMult(Expr l, Expr r) {
    return new Mult(l, r);
  }
  static public Expr newQuot(Expr l, Expr r) {
    return new Quot(l, r);
  }
  private static class Const implements Expr {
    private final int v;
    public Const(int v) {
      this.v = v;
    }
    public int eval() {
      return v;
    }
    public String toString() {
      return Integer.toString(v);
    }
  }
  private static class Plus implements Expr {
    private final Expr l;
    private final Expr r;
    public Plus(Expr l, Expr r) {
      if ((l == null) || (r == null)) {
        throw new IllegalArgumentException();
      }
      this.l = l;
      this.r = r;
    }
    public int eval() {
      return l.eval() + r.eval();
    }
    public String toString() {
      return l.toString() + " " + r.toString() + " +";
    }
  }
  private static class Minus implements Expr {
    private final Expr l;
    private final Expr r;
    public Minus(Expr l, Expr r) {
      if ((l == null) || (r == null)) {
        throw new IllegalArgumentException();
      }
      this.l = l;
      this.r = r;
    }
    public int eval() {
      return l.eval() - r.eval();
    }
    public String toString() {
      return l.toString() + " " + r.toString() + " -";
    }
  }
  private static class Mult implements Expr {
    private final Expr l;
    private final Expr r;
    public Mult(Expr l, Expr r) {
      if ((l == null) || (r == null)) {
        throw new IllegalArgumentException();
      }
      this.l = l;
      this.r = r;
    }
    public int eval() {
      return l.eval() * r.eval();
    }
    public String toString() {
      return l.toString() + " " + r.toString() + " *";
    }
  }
  private static class Quot implements Expr {
    private final Expr l;
    private final Expr r;
    public Quot(Expr l, Expr r) {
      if ((l == null) || (r == null)) {
        throw new IllegalArgumentException();
      }
      this.l = l;
      this.r = r;
    }
    public int eval() {
      return l.eval() / r.eval();
    }
    public String toString() {
      return l.toString() + " " + r.toString() + " /";
    }
  }
}
 | 
 | 
 | 
       
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 
 | package composite.three;
public class ExprFactory {
  private ExprFactory() {}
  static public Expr newConst(int v) {
    return new Const(v);
  }
  static public Expr newPlus(Expr l, Expr r) {
    return new BinOp(l, new OpAdd(), r);
  }
  static public Expr newMinus(Expr l, Expr r) {
    return new BinOp(l, new OpSub(), r);
  }
  static public Expr newMult(Expr l, Expr r) {
    return new BinOp(l, new OpMul(), r);
  }
  static public Expr newQuot(Expr l, Expr r) {
    return new BinOp(l, new OpDiv(), r);
  }
  private static final class Const implements Expr {
    private final int v;
    public Const(int v) {
      this.v = v;
    }
    public int eval() {
      return v;
    }
    public String toString() {
      return Integer.toString(v);
    }
  }
  private static final class BinOp implements Expr {
    private final Expr l;
    private final Expr r;
    private final Op op;
    public BinOp(Expr l, Op op, Expr r) {
      if ((l == null) || (op == null) || (r == null)) {
        throw new IllegalArgumentException();
      }
      this.op = op;
      this.l = l;
      this.r = r;
    }
    public int eval() {
      return op.run(l.eval(), r.eval());
    }
    public String toString() {
      return l.toString() + " " + r.toString() + " " + op.toString();
    }
  }
  private static interface Op {
    public abstract int run(int x, int y);
  }
  private static final class OpAdd implements Op {
    public String toString() { return "+"; }
    public int run(int x, int y) { return x+y; }
  }
  private static final class OpSub implements Op {
    public String toString() { return "-"; }
    public int run(int x, int y) { return x-y; }
  }
  private static final class OpMul implements Op {
    public String toString() { return "*"; }
    public int run(int x, int y) { return x*y; }
  }
  private static final class OpDiv implements Op {
    public String toString() { return "/"; }
    public int run(int x, int y) { return x/y; }
  }
}
 | 
 | 
 | 
       
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 
 | package composite.three;
public class ExprFactory2 {
  private ExprFactory2() {}
  static public Expr newConst(int v) {
    return new Const(v);
  }
  static public Expr newPlus(Expr l, Expr r) {
    return new PlusOp(l, r);
  }
//  static public Expr newMinus(Expr l, Expr r) {
//    return new BinOp(l, new OpSub(), r);
//  }
//  static public Expr newMult(Expr l, Expr r) {
//    return new BinOp(l, new OpMul(), r);
//  }
//  static public Expr newQuot(Expr l, Expr r) {
//    return new BinOp(l, new OpDiv(), r);
//  }
  private static final class Const implements Expr {
    private final int v;
    public Const(int v) {
      this.v = v;
    }
    public int eval() {
      return v;
    }
    public String toString() {
      return Integer.toString(v);
    }
  }
  private static abstract class BinOp implements Expr {
    private final Expr l;
    private final Expr r;
    private final String opString;
    public BinOp(Expr l, String opString, Expr r) {
      if ((l == null) || (r == null)) {
        throw new IllegalArgumentException();
      }
      this.l = l;
      this.r = r;
      this.opString = opString;
    }
    protected abstract int run (int x, int y);
    // to be template method, there must a template method
    // template method = method of abstract class, that calls an abstract method
    public int eval() {
      return this.run(l.eval(), r.eval());
    }
    public String toString() {
      return l.toString() + " " + r.toString() + " " + opString;
    }
  }
  private static final class PlusOp extends BinOp {
    public PlusOp(Expr l, Expr r) { super (l, "+", r); }
    public int run(int x, int y) { return x+y; }
  }
}
 | 
 | 
 | 
       
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 
 | package composite.four;
public class Main {
  public static void main(String[] args) {
    Expr onePtwo = ExprFactory.newPlus
        (ExprFactory.newConst(1), ExprFactory.newConst(2));
    ExprBuilder eb = ExprFactory.newMultBuilder();
    eb.add(ExprFactory.newConst(3));
    eb.add(ExprFactory.newConst(4));
    eb.add(onePtwo);
    Expr multiplies = eb.toExpr();
    Expr m = ExprFactory.newMinus (onePtwo, multiplies);
    System.out.println(m);
    System.out.println("Value: " + m.eval());
  }
}
 | 
 | 
 | 
         
|  | 
| | | 
0102
 03
 04
 05
 
 | package composite.four;
public interface ExprBuilder {
  Expr toExpr();
  void add(Expr e);
}
 | 
 | 
 | 
         
|  | 
| | | 
001002
 003
 004
 005
 006
 007
 008
 009
 010
 011
 012
 013
 014
 015
 016
 017
 018
 019
 020
 021
 022
 023
 024
 025
 026
 027
 028
 029
 030
 031
 032
 033
 034
 035
 036
 037
 038
 039
 040
 041
 042
 043
 044
 045
 046
 047
 048
 049
 050
 051
 052
 053
 054
 055
 056
 057
 058
 059
 060
 061
 062
 063
 064
 065
 066
 067
 068
 069
 070
 071
 072
 073
 074
 075
 076
 077
 078
 079
 080
 081
 082
 083
 084
 085
 086
 087
 088
 089
 090
 091
 092
 093
 094
 095
 096
 097
 098
 099
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 
 | package composite.four;
import java.util.List;
import java.util.LinkedList;
public class ExprFactory {
  private ExprFactory() {}
  static public Expr newConst(int v) {
    return new Const(v);
  }
  static public Expr newPlus(Expr l, Expr r) {
    return new BinOp(l, new OpAdd(), r);
  }
  static public Expr newMinus(Expr l, Expr r) {
    return new BinOp(l, new OpSub(), r);
  }
  static public Expr newMult(Expr l, Expr r) {
    return new BinOp(l, new OpMul(), r);
  }
  static public Expr newQuot(Expr l, Expr r) {
    return new BinOp(l, new OpDiv(), r);
  }
  static public ExprBuilder newPlusBuilder() {
    return new NaryOpBuilder(new OpAdd(), new Const(0));
  }
  static public ExprBuilder newMultBuilder() {
    return new NaryOpBuilder(new OpMul(), new Const(1));
  }
}
final class Const implements Expr {
  private final int v;
  public Const(int v) {
    this.v = v;
  }
  public int eval() {
    return v;
  }
  public String toString() {
    return Integer.toString(v);
  }
}
final class BinOp implements Expr {
  private final Expr l;
  private final Expr r;
  private final Op op;
  public BinOp(Expr l, Op op, Expr r) {
    if ((l == null) || (op == null) || (r == null)) {
      throw new IllegalArgumentException();
    }
    this.op = op;
    this.l = l;
    this.r = r;
  }
  public int eval() {
    return op.eval(l.eval(), r.eval());
  }
  public String toString() {
    return l.toString() + " " + r.toString() + " " + op.toString();
  }
}
final class NaryOp implements Expr {
  private final Expr[] args;
  private final Expr zero;
  private final Op op;
  public NaryOp(Expr[] args, Op op, Expr zero) {
    // Don't need to test these, since the builder checks them.
    //     if ((args == null) || (op == null) || (zero == null))
    //       throw new IllegalArgumentException();
    //     for (int i=0; i<args.length; i++)
    //       if (args[i] == null)
    //         throw new IllegalArgumentException();
    this.op = op;
    this.args = args;
    this.zero = zero;
  }
  public int eval() {
    int result = zero.eval();
    for (int i=0; i<args.length; i++)
      result = op.eval(result, args[i].eval());
    return result;
  }
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("[");
    for (int i=0; i<args.length; i++) {
      sb.append(args[i].toString());
      if (i+1<args.length)
        sb.append(", ");
    }
    sb.append("]");
    sb.append(op.toString());
    sb.append(" ");
    return sb.toString();
  }
}
final class NaryOpBuilder implements ExprBuilder {
  private final List<Expr> args;
  private final Expr zero;
  private final Op op;
  public NaryOpBuilder(Op op, Expr zero) {
    if ((op == null) || (zero == null))
      throw new IllegalArgumentException();
    this.args = new LinkedList<Expr>();
    this.op = op;
    this.zero = zero;
  }
  public void add(Expr e) {
    if (e == null)
      throw new IllegalArgumentException();
    args.add(e);
  }
  public Expr toExpr() {
    return new NaryOp(args.toArray(new Expr[0]), op, zero);
  }
}
interface Op {
  public abstract int eval(int x, int y);
}
final class OpAdd implements Op {
  public String toString() { return "+"; }
  public int eval(int x, int y) { return x+y; }
}
final class OpSub implements Op {
  public String toString() { return "-"; }
  public int eval(int x, int y) { return x-y; }
}
final class OpMul implements Op {
  public String toString() { return "*"; }
  public int eval(int x, int y) { return x*y; }
}
final class OpDiv implements Op {
  public String toString() { return "/"; }
  public int eval(int x, int y) { return x/y; }
}
 | 
 | 
 | 
       
 
        
          Remember the awful finite state machine from Homework 3?
        
        file:Control.java [source] [doc-public] [doc-private]
        
          Here is a version refactored to the state pattern:
        
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 
 | package state.ui.main;
import state.ui.UI;
import state.ui.UIMenu;
import state.ui.UIMenuBuilder;
class Control {
  final State EXITED;
  final State EXIT;
  private State state;
  Control(UI ui) {
    EXITED = new ExitedState();
    EXIT = new ExitState(this,ui);
    state = EXIT;
  }
  void run() {
    while (state != EXITED) {
      state = state.run();
    }
  }
}
interface State {
  public State run();
}
final class ExitedState implements State {
  public State run() {
    return this;
  }
}
final class ExitState implements State {
  Control control;
  UI ui;
  UIMenu m;
  ExitState(Control control, UI ui) {
    this.control = control;
    this.ui = ui;
    UIMenuBuilder mb;
    mb = new UIMenuBuilder();
    //mb.add("Default", new UIMenuAction() { public Object run() {return this;} });
    mb.add("Default", () -> this);
    mb.add("Yes", () -> control.EXITED);
    mb.add("No", () -> control.EXIT);
    this.m = mb.toUIMenu("Are you sure you want to exit?");
  }
  public State run() {
    return (State) ui.processMenu(m);
  }
}
 | 
 | 
 | 
        
          Full code:
          dir:state/ui [source]
        
       
 
         
       
 
        
          Discuss intrinsic/extrinsic state
          and field/parameter refactorings.
        
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | package state.one;
interface I {
  public int f();
  public int g();
  public void changeDirection();
}
class C implements I {
  private boolean state;
  private int i;
  private int j;
  public int f() {
    if (state)
      i += 26;
    else
      i -= 32;
    return i;
  }
  public int g() {
    if (state)
      j += 42;
    else
      j -= 27;
    return j;
  }
  public void changeDirection() {
    state = !state;
  }
}
 | 
 | 
 | 
       
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 
 | package state.five;
interface I {
  public int f();
  public int g();
  public void changeDirection();
}
class C implements I {
  private State state = new StateMinus();
  private int i;
  private int j;
  public int f() {
    return state.f();
  }
  public int g() {
    return state.g();
  }
  public void changeDirection() {
    state = state.next();
  }
  interface State {
    public int f();
    public int g();
    public State next();
  }
  class StateMinus implements State {
    public int f() {
      i -= 32;
      return i;
    }
    public int g() {
      j -= 27;
      return j;
    }
    public State next() {
      return new StatePlus();
    }
  }
  class StatePlus implements State {
    public int f() {
      i += 26;
      return i;
    }
    public int g() {
      j += 42;
      return j;
    }
    public State next() {
      return new StateMinus();
    }
  }
}
 | 
 | 
 | 
       
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 
 | package state.four;
interface I {
  public int f();
  public int g();
  public void changeDirection();
}
class C implements I {
  private CState state = new CStateMinus(this);
  int i;
  int j;
  public int f() {
    return state.f();
  }
  public int g() {
    return state.g();
  }
  public void changeDirection() {
    state = state.next();
  }
}
interface CState {
  public int f();
  public int g();
  public CState next();
}
class CStateMinus implements CState {
  C x;
  CStateMinus(C x) { this.x = x; }
  public int f() {
    x.i -= 32;
    return x.i;
  }
  public int g() {
    x.j -= 27;
    return x.j;
  }
  public CState next() {
    return new CStatePlus(x);
  }
}
class CStatePlus implements CState {
  C x;
  CStatePlus(C x) { this.x = x; }
  public int f() {
    x.i += 26;
    return x.i;
  }
  public int g() {
    x.j += 42;
    return x.j;
  }
  public CState next() {
    return new CStateMinus(x);
  }
}
 | 
 | 
 | 
       
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 
 | package state.two;
interface I {
  public int f();
  public int g();
  public void changeDirection();
}
class C implements I {
  private CState[] states = new CState[] { new CStateMinus(), new CStatePlus() };
  private int index;
  int i;
  int j;
  public int f() {
    return states[index].f(this);
  }
  public int g() {
    return states[index].g(this);
  }
  public void changeDirection() {
    index = (index+1) % 2;
  }
}
interface CState {
  public int f(C x);
  public int g(C x);
}
class CStateMinus implements CState {
  public int f(C x) {
    x.i -= 32;
    return x.i;
  }
  public int g(C x) {
    x.j -= 27;
    return x.j;
  }
}
class CStatePlus implements CState {
  public int f(C x) {
    x.i += 26;
    return x.i;
  }
  public int g(C x) {
    x.j += 42;
    return x.j;
  }
}
 | 
 | 
 | 
       
 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | package state.three;
interface I {
  public int f();
  public int g();
  public void changeDirection();
}
class C implements I {
  private CState state = CState.MINUS;
  int i;
  int j;
  public int f() {
    return state.f(this);
  }
  public int g() {
    return state.g(this);
  }
  public void changeDirection() {
    state = (state==CState.MINUS) ? CState.PLUS : CState.MINUS;
  }
}
 | 
 | 
 | 
         
|  | 
| | | 
0102
 03
 04
 05
 06
 07
 08
 09
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | package state.three;
interface CState {
  public int f(C x);
  public int g(C x);
  public static final CState MINUS = new CStateMinus();
  public static final CState PLUS = new CStatePlus();
}
class CStateMinus implements CState {
  public int f(C x) {
    x.i -= 32;
    return x.i;
  }
  public int g(C x) {
    x.j -= 27;
    return x.j;
  }
}
class CStatePlus implements CState {
  public int f(C x) {
    x.i += 26;
    return x.i;
  }
  public int g(C x) {
    x.j += 42;
    return x.j;
  }
}
 | 
 | 
 | 
      
      Revised: 2008/02/12 20:46