Idioms and patterns

2


Additional keywords and phrases: generic types, assertions, canonical classes, event-driven computation


slide: Idioms and patterns

subsections:



  public class envelope { 
envelope
public envelope() { } public void message() { System.out.println("hello ... "); } };

slide: Hello World



slide: Envelope/Letter Factory



  public class envelope { 
envelope
letter impl; public envelope() { impl = new letter(); } public void message() { impl.message(); } };


  public class letter { 
letter
public letter() { } public void message() { System.out.println("Message in a letter"); } };

slide: Envelope/Letter



  public class factory { 
factory
public factory() { } letter letter() { return new letter(); } envelope envelope() { return new envelope(); } };

  public class envelope { 
envelope
letter impl; public envelope() { factory f = new factory(); impl = f.letter(); // obtained from factory } public void message() { impl.message(); } };

slide: Factory



  public class singleton extends letter {  
singleton
static int number = 0; protected singleton() { } static letter instance() { if (number==0) { theletter = new letter(); number = 1; } return theletter; } public void message() { System.out.println("Message in a letter"); } static letter theletter; };

slide: Singleton letter


Overloading

print



  extern void print(int);
  extern void print(float);
  

Generic class -- templates

list< T >


  template< class T > class list { ... }
  list* alist; 
  

Polymorphism by inheritance

shape



  class shape { ... };
  class circle : public shape { ... } 
  shape* s = new circle;
  

slide: Polymorphic type declarations


Standard Template Library

STL



slide: The Standard Template Library



  double sqrt( double arg ) { 
sqrt
require ( arg >= 0 ); double r=arg, x=1, eps=0.0001; while( fabs(r - x) > eps ) { r=x; x=r-((r*r-arg)/(2*r)); } promise ( r - arg * arg <= eps ); return r; }

slide: Using assertions in C++



  class counter { 
counter
public: counter(int n = 0) : _n(n) { require( n >= 0 ); promise( invariant() ); // check initial state } virtual void operator++() { require( true ); // empty pre-condition hold(); // save the previous state _n += 1; promise( _n == old_n + 1 && invariant() ); } int value() const { return _n; } // no side effects virtual bool invariant() { return value() >= 0; } protected: int _n; int old_n; virtual void hold() { old_n = n; } };

slide: The counter contract



  class bounded : public counter { 
bounded
public: bounded(int b = MAXINT) : counter(0), max(b) {} void operator++() { require( value() < max ); // to prevent overflow counter::operator++(); } bool invariant() { return value() <= max && counter::invariant(); } private: int max; };

slide: Refining the counter contract


Canonical class in C++

Abstract data types must be indistinguishable from built-in types


slide: Canonical class

subsections:


hush classes">

Basic hush classes


slide: Basic


    interface kit { 
kit
void eval(string cmd); string result(); void bind(string name, handler h); };


     interface handler { 
handler
int dispatch( event e );
to dispatch events

int operator(); };


     interface widget : handler { 
widget
... void bind( handler h ); void bind( string action, handler h ); ... };


     interface event : handler { 
event
operator(); };


  class A { 
A -- naive
public A() { } public void f1() { System.out.println("A.f1"); f2(); } public void f2() { System.out.println("A.f2"); } };

slide: Running example



  class A { 
A
public A() { body = new BodyOfA(this); } protected A(int x) { } public void f1() { body.f1(); } public void f2() { body.f2(); } public void f3() { System.out.println("A.f3"); } private A body; };

slide: Interface: A



  class BodyOfA extends A { 
BodyOfA -- naive
public BodyOfA() { super(911); } public void f1() { System.out.println("A.f1"); f2(); } public void f2() { System.out.println("A.f2"); } };

slide: Naive: BodyOfA



  class C extends A { 
C
public void f2() { System.out.println("C.f2"); } };

slide: Usage: C



    C c = new C; c.f1();    
  

slide: Example: calling C



  class BodyOfA extends A { 
BodyOfA
public BodyOfA(A h) { super(911); handle = h; } public void f1() { System.out.println("A.f1"); handle.f2(); } public void f2() { System.out.println("A.f2"); } A handle; // reference to invocation context };

slide: Handle/Body: BodyOfA



slide: Separating interface hierarchy and implementation



  class item { 
item
public item(String x) { _name = x; _self = null; } String name() { return exists()?self().name():_name; } public void redirect(item x) { _self = x; } boolean exists() { return _self != null; } public item self() { return exists()?_self.self():this; } item _self; String _name; };

slide: Item with self()



  public class go {
  
  public static void main(String[] args) {
  	item a = new item("a");
  	item b = new item("b");
  	a.redirect(b);
  	System.out.println(a.name()); 
indeed, b
} };

slide: item: go



  class actor { 
actor
public static final int Person = 0; public static final int Student = 1; public static final int Employer = 2; public static final int Final = 3; public void walk() { if (exists()) self().walk(); } public void talk() { if (exists()) self().talk(); } public void think() { if (exists()) self().think(); } public void act() { if (exists()) self().act(); } public boolean exists() { return false; } public actor self() { return this; } public void become(actor A) { } public void become(int R) { } };

slide: actor.java



  class student extends actor { 
student
public void talk() { System.out.println("OOP"); } public void think() { System.out.println("Z"); } };

  class employer extends actor { 
employer
public void talk() { System.out.println("money"); } public void act() { System.out.println("business"); } };

slide: Students and Employers



  class person extends actor { 
person
public person() { role = new actor[ Final+1 ]; for( int i = Person; i <= Final; i++ ) role[i]=this; become(Person); } public boolean exists() { return role [role] != this; } public actor self() { if ( role[ Person ] != this ) return role[ Person ].self(); else return role [role]; } public void become(actor p) { role[ Person ] = p; } public void become(int R) { if (role[ Person ] != this) self().become(R); else { _role = R; if ( role [role] == this ) { switch(_role) { case Person: break; // nothing changes case Student: role [role] = new student(); break; case Employer: role [role] = new employer(); break; case Final: role [role] = new actor(); break; default: break; // nothing happens } } } } int _role; actor role[]; };

slide: person.java



  class adult extends person {  
adult
public void talk() { System.out.println("interesting"); } };

slide: adult.java



  public class go { 
example
public static void main(String[] args) { person p = new person(); p.talk(); // empty p.become(actor.Student); p.talk(); // OOP p.become(actor.Employer); p.talk(); // money p.become(new adult()); p.talk(); // interesting p.become(actor.Student); p.talk(); // OOP p.become(p); p.talk(); // old role: employer p.become(actor.Person); p.talk(); // initial state } };

slide: go.java


Invocation context

handle/body


Problem
Inheritance breaks with handle/body
Background
Envelope/Letter, hiding implementations
Realization
Explicit invocation contact in body
Usage
sessions, events, kits, widgets, items

slide: Invocation context


Nested components

virtual self-reference


Problem
Realizing composites with single inheritance
Background
Decorators, prototypes
Realization
Smart delegation
Usage
Composite widgets, embedded logic

slide: Nested components


Actor pattern

dynamic role switching


Problem
Static type hierarchies may be too limited
Background
State transitions, self-reference
Realization
Dynamic instantiation and delegation
Usage
Web viewer, kit -- embedded logic

slide: Actor pattern

subsections:


A catalogue of design patterns

 [GOF94]



slide: A catalogue of design patterns


pattern schema


Name -- handle

Problem -- when to apply

Solution -- general arrangement

Consequences -- tradeoffs


slide: The pattern schema


design for change


slide: Causes for redesign


Creational patterns

See Pattern Lectures


slide: Creational patterns

Structural patterns

PatternAliasRemarks
Composite part/whole collections of components
Flyweight handle/body extrinsic state, many objects
Adaptor wrapper resolve inconsistency between interfaces
Bridge handle/body relate abstraction to implementation
Decorator handle/body to introduce additional functionality
Facade handle/body provides unified interface
Proxy handle/body to defer ... remote, virtual, protection

Behavioral patterns

cooperation

  • algorithms and the assignment of responsibilities between objects

class

  • Template Method -- the skeleton of an algorithm
  • Interpreter -- to evaluate expressions

object

composition

  • Mediator -- provides indirection
  • Chain of Responsibility -- connect objects to interact
  • Observer -- to handle dependencies

slide: Behavioral patterns


Encapsulating behavior

objectify!


slide: Encapsulating behavior


Observer

Consequences


slide: Observer pattern



slide: The Observer pattern

subsections:


The Reactor pattern

See D.C. Schmidt, Using Design Patterns to Develop Reusable Object-oriented Communication Software, CACM October '95, 38(10): 65-74


slide: The Reactor pattern



slide: The Reactor pattern -- structure



slide: The Reactor Pattern - interaction



  th = new centigrade();
  th = new fahrenheit();
  th.set(f);
  f = th.get();
  

For thermometer th, th1; float f;


slide: Abstract system -- thermometers


  class thermometer { 
thermometer
protected thermometer( float v ) { temp = v; } public void set(float v) { temp = v; } public float get() { return temp; } protected float temp; };


  class centigrade extends thermometer { 
centigrade
public centigrade() { super(0); } public void set(float v) { temp = v + 273; } public float get() { return temp - 273; } };


  class fahrenheit extends thermometer { 
fahrenheit
public fahrenheit() { super(0); } public void set(float v) { temp = (v - 32) * 5/9 + 273; } public float get() { return temp * 9/5 + 32 - 273; } };


  class displayer extends window { 
displayer
public displayer() { ... } public void put(String s) { ... } public void put(float f) { ... } };


  class prompter extends window { 
prompter
public prompter(String text) { ... } public float get() { ... } public String gets() { ... } };


  abstract class event { 
event
pubic void dependent(event e) { ... } pubic void process() { ... } public void operator(); // abstract method private event[] dep; };


  class update extends event { 
update
public update(thermometer th, prompter p) { _th =th; _p = p; } void operator()() { _th.set( _p.get() ); process(); } thermometer _th; prompter _p; };


  class show extends event { 
show
public show(thermometer th, displayer d) { _th = th; _d = d; } public void operator() { _d.put( _th.get() ); process(); } thermometer _th; displayer _d; };


  thermometer c = new centigrade();
  thermometer f = new fahrenheit();
  
  displayer cd = new displayer("centigrade");
  displayer fd = new displayer("fahrenheit");
  
  prompter cp = new prompter("enter centigrade value");
  prompter fp = new prompter("enter fahrenheit value");
  
  show sc = new show(c,cd);
  show sf = new show(f,fd);
  
  update uc = new update(c,cp);
  update uf = new update(f,fp);
  


  uc.dependent(sc);
  uc.dependent(sf);
  uf.dependent(sc);
  uf.dependent(sf);
  


  menu.insert(uc);
  menu.insert(uf);
  

Polymorphism

1



slide: Section 2.1: Polymorphism


hush">

Idioms in hush

2



slide: Section 2.2: Idioms in


A catalogue of design patterns

3



slide: Section 2.3: A catalogue of design patterns


Event-driven computation

4



slide: Section 2.4: Event-driven computation

  1. How would you explain the letter/envelope idiom?
  2. Characterize the notion of polymorphism. Give some examples.
  3. What is a canonical class? Characterize its ingredients and give an example.
  4. Give a brief description of the handle/body idiom, virtual self-reference, and dynamic role switching.
  5. What kinds of patterns can you distinguish? Why do you consider patterns to be of relevance?
  6. Give a detailed description of the Factory pattern and also of the Observer pattern.
  7. Describe the Reactor pattern. Why is it useful?
  8. Give an example of a system based on event-driven computation.

Further reading

For an introduction to Java, there is ample choice. An excellent online tutorial can be found on java.sun.com/docs/books/tutorial . As textbooks on C++ I recommend  [Lippman91], and for the more advanced reader  [Stroustrup98]. For an extensive introduction to STL, read  [STL].  [Coplien92] is the original introduction to idioms in C++. The by now classical book for patterns is  [GOF94]. Well worth reading are the many articles in the POPL proceedings,  [POPL1],  [POPL2] and  [POPL3].