Principles of ObjectOriented Software Development Idioms and Patterns
Principles of Object-Oriented Software Development Idioms and Patterns
Idioms and Patterns Introduction Polymorphism Idioms in hush A catalogue of design patterns Event-driven computation Summary Q/A Literature
Idioms and Patterns • • polymorphism -- inheritance and delegation idioms -- realizing concrete types patterns -- a catalogue of design patterns events -- the reactor pattern Additional keywords and phrases: generic types, assertions, canonical classes, event-driven computation
Polymorphism Subsections: Inheritance and delegation in Java Polymorphism in C++ Assertions in C++ Canonical class idioms
Inheritance and delegation in Java public class envelope { enve lope public envelope() { } public void message() { System. out. println("hello. . . "); } };
Envelope/letter pattern Factory
public class envelop { letter impl; public envelope() { impl = new letter(); } envelope public void message() { impl. message(); } }; public class letter { public letter() { } public void message() { System. out. println("Message in a letter"); } letter
public class factory { public factory() { } factory letter() { return new letter(); } envelope() { return new envelope(); } }; public class envelope { letter impl; public envelope() { factory f = new factory(); impl = f. letter(); // obtained from factory } public void message() { impl. message(); } }; envelope
public class singleton extends letter { 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; }; singleton
Polymorphism in C++ Overloading print extern void print(int); extern void print(float); Generic class -- templates list< T > template< class T > class list {. . . } list<int>* alist; Polymorphism by inheritance class shape {. . . }; class circle : public shape {. . . } shape* s = new circle; shape
Standard Template Library • • • containers -- to hold objects algorithms -- act on containers iterators -- to traverse containers functions -- as objects adaptors -- to transform objects allocators -- for memory management
Assertions in C++ double sqrt( double arg ) { 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 (arg - r * r <= eps ); return r; } sqrt
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; } };
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; };
Canonical class idioms
Canonical class in C++ • • • default constructor copy constructor destructor assignment operators Abstract data types must be indistinguishable from built-in types
Idioms in hush Subsections The handle/body idiom Virtual self-reference Dynamic role switching The art of hush programming
The hush framework basic concepts
Basic hush classes • session -- to manage (parts of) the application • kit -- to provide access to the underlying system and interpreter • handler -- to bind C++ functionality to events • event -- stores information concerning user actions or system events • widget -- to display information on a screen • item -- represents an element of a widget
kit interface kit { kit void eval(string cmd); string result(); void bind(string name, handler h); };
handler interface handler { handl er int dispatch( event e ); // to dispatch events int operator(); };
widget interface widget : handler {. . . void bind( handler h ); void bind( string action, handler h ); . . . }; widget
event interface event : handler { operator(); }; event
The Handle/Body Idiom class A { A -- naive public A() { } public void f 1() { System. out. println("A. f 1"); f 2(); } public void f 2() { System. out. println("A. f 2"); } };
class A { A public A() { body = new Body. Of. A(this); } protected A(int x) { } public void f 1() { body. f 1(); } public void f 2() { body. f 2(); } public void f 3() { System. out. println("A. f 3"); } private A body; }; Interface: A
class Body. Of. A extends A { Body. Of. A -- naive public Body. Of. A() { super(911); } public void f 1() { System. out. println("A. f 1"); f 2(); } public void f 2() { System. out. println("A. f 2"); } }; class C extends A { C public void f 2() { System. out. println("C. f 2"); } }; slide: Usage: C C c = new C; c. f 1(); // instantiate
class Body. Of. A extends A { Body. Of. A public Body. Of. A(A h) { super(911); handle = h; } public void f 1() { System. out. println("A. f 1"); handle. f 2(); } public void f 2() { System. out. println("A. f 2"); } A handle; }; reference to invocation context
Virtual self-reference class item { public item(String x) { _name = x; _self = null; } item 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(): this; } item _self; String _name; };
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
Dynamic role-switching
class 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) { } }; actor
class student extends actor { student public void talk() { System. out. println("OOP"); } public void think() { System. out. println("Z"); } }; class employer extends actor { public void talk() { System. out. println("money"); } public void act() { System. out. println("business"); } }; employer
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[]; };
class adult extends person { adult public void talk() { System. out. println("interesting"); } };
public class go { 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(); p. become(new adult()); p. talk(); p. become(actor. Student); p. talk(); p. become(p); p. talk(); p. become(actor. Person); p. talk(); } }; example money interesting OOP old role: employer // initial state
The art of hush programming
Invocation Context Problem Inheritance breaks with handle/body Background Envelope/Letter, hiding implementations Realization Explicit invocation contact in body Usage sessions, events, kits, widgets, items handle/body
Nested Components virtual self-reference Problem Realizing composites with single inheritance Background Decorators, Prototypes Realization Smart delegation Usage Composite widgets, Embedded logic
Actor Pattern dynamic role switching Problem Static type hiearchies may be too limited Background State transitions, self-reference Realization Dynamic instantiation and delegation Usage Web viewer, kit -- embedded logic
A catalogue of design patterns Subsections: Creational Patterns Structural Patterns Behavioral Patterns
A Catalogue of Design Patterns • • a common design vocabulary documentation and learning aid an adjunct to existing methods a target for redesign
The Pattern Schema Name - handle increases design vocabulary Problem - when to apply explains the problem and the conflict Solution - general arrangement design, responsibilities, collaborations Consequences - tradeoffs to understand the costs and benefits
Causes for Redesign for change • creating an object by specifying a class explicitly -- Abstract Factory, Factory Method, Prototype • dependence on specific operations -- Chain of Responsibilty, Command • dependence on hardware & software platforms -- Abstract Factory, Bridge • dependence on object implementation or representation --Abstract Factory, Bridge, Memento, Proxy
• algorithm dependence -- Iterator, Strategy, Template Method, Visitor • extending functionality by subclassing -Bridge, Composite, Decorator, Observer • tight coupling -- Abstract Factory, Bridge, Chain of Responsibilities, Command, Facade, Mediator, Observer • inability to alter classes conveniently -Adaptor, Decorator,
Creational Patterns
Creational Patterns • • Factory -- hide concrete classes Factory Method -- virtual constructors Prototype -- dynamic creation by cloning Singleton -- one instance only
Structural Patterns object and class composition Pattern Composite Flyweight Adaptor Bridge Decorator Facade Proxy Alias Remarks part/whole collections of components part/whole* extrinsic state, many objects wrapper resolves inconsistencies handle/body abstraction to implementation wrapper to introduce functionality wrapper* provides unified interface surrogate 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 Mediator -- provides indirection Chain of Responsibility -- connect objects to interact Observer -- to handle dependencies composition
Encapsulating behavior objectify! • • • Command -- action + undo Strategy -- choice of algorithms Visitor -- decouple traversal and operations Iterator -- access and traversal State -- object state -> behavioral change
The Observer Pattern Observer one-to-many dependencies and notification Consequences abstract coupling between subject and observer constraint propagation deals with unexpected updates
Event-driven computation Subsections: The Reactor Pattern Abstract event systems
The Reactor Pattern • activate handlers when events occur • allow events from multiple sources • in single threaded process See D. C. Schmidt, Using Design Patterns to Develop Reusable Object-oriented Communication Software, CACM October '95, 38(10): 65 -74
Abstract event systems th = new centigrade(); th = new fahrenheit(); th. set(f); f = th. get(); For thermometer th, th 1; float f; Abstract system -- thermometers
class thermometer { protected thermometer( float v ) { temp = v; } public void set(float v) { temp = v; } public float get() { return temp; } protected float temp; }; thermometer
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 { public fahrenheit() { super(0); } public void set(float v) { temp = (v - 32) * 5/9 + 273; } public float get() { return temp * 9/5 + 32 - 273; } }; fahrenheit
class displayer extends window { displayer public displayer() {. . . } public void put(String s) {. . . } public void put(float f) {. . . } }; class prompter extends window { public prompter(String text) {. . . } public float get() {. . . } public String gets() {. . . } }; prompter
abstract class event { pubic void dependent(event e) {. . . } pubic void process() {. . . } public void operator(); // abstract method private event[] dep; }; event
class update extends event { public update(thermometer th, prompter p) { _th =th; _p = p; } void operator()() { _th. set( _p. get() ); process(); } thermometer _th; prompter _p; }; update
class show extends event { public show(thermometer th, displayer d) { _th = th; _d = d; } public void operator() { _d. put( _th. get() ); process(); } thermometer _th; displayer _d; }; show
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); Installing the objects
uc. dependent(sc); uc. dependent(sf); uf. dependent(sc); uf. dependent(sf); Assigning dependencies
Summary
1 Polymorphism • • inheritance and delegation in Java polymorphism in C++ assertions in C++ canonical class idioms
2 Idioms in hush • • the handle/body idiom virtual self-reference dynamic role switching the art of hush programming
3 A catalogue of design patterns • creational patterns • structural patterns • behavioral patterns
4 Event-driven computation • the Reactor pattern • abstract event systems
Questions 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 selfreference, 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 http: //java. sun. com/docs/books/tutorial As textbooks on C++ I recommend [Lippman 91], and for the more advanced reader [Stroustrup 98]. For an extensive introduction to STL, read [STL]. [Coplien 92] is the original introduction to idioms in C++. The by now classical book for patterns is [GOF 94]. Well worth reading are the many articles in the POPL proceedings, [POPL 1], [POPL 2], [POPL 3].
- Slides: 73