6894 · workshop in software design lecture 5 · october 14, 1998 · design patterns
DESCRIPTION
6894 · workshop in software design lecture 5 · october 14, 1998 · design patterns. topics. schedule October 19 reading on concurrent design patterns catalog of about 10 design patterns http://gee.cs.oswego.edu/dl/cpj/index.html October 21 instead of Problem Frames, discuss design proposals - PowerPoint PPT PresentationTRANSCRIPT
daniel jacksonmit lab for computer science
6894 · workshop in software designlecture 5 · october 14, 1998 · design patterns
04/19/23 daniel jackson 2
topics
schedule· October 19
reading on concurrent design patternscatalog of about 10 design patterns
http://gee.cs.oswego.edu/dl/cpj/index.html
· October 21instead of Problem Frames, discuss design proposalseach team bring a 5-10 minute presentation
design proposals· scope
can be on some aspect of the CMon an entire redesign of the CM
· form1. problem addressed2. solution proposed3. strategy, esp. minimal subset
04/19/23 daniel jackson 3
origins
motivation· capture expertise of experienced designers· reuse of design practice and form· provide vocabulary for design
history· Christopher Alexander et al: A Pattern Language (1977)· Erich Gamma’s PhD thesis (1991): about half of the GOF patterns· Coplien: Advanced C++ Styles and Idioms (1992)· Helm, Vlissides, Johnson: summary of pattern catalog in ECOOP (1993)· Gamma et al: Design Patterns (1995)
often referred to as the Gang of Four Book (GOF)
04/19/23 daniel jackson 4
how patterns help
flexibility· make code less susceptible to changes· confine changes as much as possible· examples: confine changes in …
representation (Factory, Bridge, Memento, Proxy)algorithm (Builder, Iterator, Strategy, Template, Visitor)platform (Factory, Bridge)adding new features (Observer, State, Mediator)
documentation· patterns are familiar to programmers· name alone says a lot
archaeology· patterns record best practices· target for research ideas, language evaluation, etc
04/19/23 daniel jackson 5
what’s in a pattern?
GOF style presentation· name
very important!· problem
difficulty addressed by patternmotivating example
· solutiongeneral form of patternimplementation advicevariants
· consequencesnot just benefits – liabilities tooall patterns add complexitymost reduce efficiency
04/19/23 daniel jackson 6
how patterns work
standard use of language constructs· algebraic datatypes (Composite)· closures (Factory)· class variables (Singleton)· inheritance (Template) – but maybe not standard use?
ad hoc tricks· hand-coded dispatch (Visitor)· dynamic reclassification (State)· cloning + cursor (Iterator)
opaque association· (my term)· Adapter, Bridge, Mediator, Observer, Proxy
04/19/23 daniel jackson 7
GOF bias: delegation over inheritance
example· Window and Rectangle· with inheritance
Window subclass of RectanglegetArea method of Window is inheritedresize method of Window calls methods and uses instance vars of
Rectangle· with delegation
Window’s rep includes a RectanglegetArea method of Window just invokes getArea of Rectangle
advantages of delegation· runtime composition: Window can become circular by switching Rep· better modularity: avoid abstraction violations of inheritance
disadvantages of delegation· a bit clumsier than inheritance· objects have distinct types: can’t pass Window to method expecting Rectangle
but Window is probably not a subtype of Rectangle anywayless of an issue in dynamically-typed languages, eg. Scheme
04/19/23 daniel jackson 8
GOF bias: others
no parametric polymorphism· most useful at lower level of abstraction?
notion of association (from OMT) hides representation of set or table
objects, not functions· closures rarely used
with exception of Visitor, State, …?· patterns are very imperative in flavour
04/19/23 daniel jackson 9
opaque association
motivation· behaviour of two objects A and B is tightly coupled· want coupling only at runtime, not compile time
change to B’s code should not affect A’s
basic idea· loosen compile time coupling by
having A access B through an opaque associationA’s code no longer depends on B’s interface
two ways to achieve· indirection
A accesses B through another object, X· specification
A accesses B as if it has a specification S that is weaker than its actual specification
consequences of this style of design· more complex compile-time structure· greater disparity between compile-time and runtime structures· more elaborate runtime invariants
04/19/23 daniel jackson 10
class models
elements· a box represents a class· a bar represents a specification· an arrow from box A to box B means
A’s code calls a method on a B object· an arrow from A to B through spec S
A’s code calls a method of a B object, but views B as having spec S
if arrow is dotted, association is transient: B object not in rep of A
A B
A B
S
04/19/23 daniel jackson 11
why yet another notation?
object model plays two roles· abstract state
what objects exist, what invariants hold, etc· class structure
what code modules exist, dependences, namespace, etc
shouldn’t be conflated· specs are not just sets of objects!
spec describes what properties are expected in the future· class structure should be postponed
abstract state description is a specification activityallocation of methods and state to classes is a design activity
· design patterns suggest major deviation from problem domain structure
snags caused by shared notation· OCL’s typecasts: much more complex than Alloy’s simple set ops· no superclass/interface distinction· only one occurrence of an interface node with a given name
so Enumeration, eg, can only occur once!but different Enumerations often unrelated
04/19/23 daniel jackson 12
disentangling design patterns: observer
essential feature· ConcreteSubject views ConcreteObserver through Observer· code sharing in Subject is a minor detail
Subject
Attach (Observer)Detach (Observer)Notify ()
Concrete Subject
GetState ()SetState ()
subjectState
Concrete Observer
Update ()
observerState
Observer
Update ()
subject
observers
for all o in observers { o.Update (); }
observerState = subject.GetState ()
return subjectState
*
!
04/19/23 daniel jackson 13
examples of opaque association (1)
CLIENT ADAPTER ADAPTEE
TARGETadapter
CLIENT PROXY SERVICE
SERVICEproxy
CLIENT REFINEDIMPL-A
ABSTRACTION IMPL-Bbridge
04/19/23 daniel jackson 14
examples of opaque association (2)
COLL-1 CMEDIATOR COLL-2
MEDIATORmediator
CSUBJECT COBSERVER
OBSERVERobserver
CLIENT CONTEXTSTATE-A
STATE-Bstate STATE
04/19/23 daniel jackson 15
examining a DP: visitor
visitor is unusual· designed to overcome OO-ness of OO language· a great idea or a clever hack?· discussed in detail in
Felleisen & Friedman, A Little Java, A Few Patterns
ELEMENT-A
ELEMENT-B
VISITOR-X
04/19/23 daniel jackson 16
visitor example
AST for arithmetic expressions· suppose language is
expr ::= literal | variable | expr + expr | expr * expr | - expr· might implement as AST with:
interface Exprclass Literal implements Exprclass Variable implements Exprabstract class BinaryExpr implements Exprclass MinusExpr implements Expr
operations on AST· evaluate for given binding of variables to literals· pretty print· reduce (eg, replace e + 0 by e)
observation· many involve similar traversals· awkward to implement each new operation by adding method to each class· would rather add a new class for each operation
04/19/23 daniel jackson 17
sample Visitor code
interface Visitor { void for_Literal (Literal x); void for_Variable (Variable x); void for_BinaryExpr (BinaryExpr x); void for_MinusExpr (MinusExpr x); }
class Literal implements Expr { … void accept (Visitor v) { v.for_Literal (this); } }
class PrettyPrintV implements Visitor { PrettyPrintV () {}; void for_Literal (Literal x) { System.out.println (x.toString()); } void for_BinaryExpr (BinaryExpr x) { x.left.accept (this); System.out.println (x.op.toString()); x.right.accept (this); } }
note· Visitor accesses representation of visited class!
04/19/23 daniel jackson 18
visitor as closure
basic idea· visitor provides convenient context for state to be maintained over traversal
examples· encapsulate output stream
PrettyPrintV (Stream s) {stream = s;}void for_Literal (Literal x) {stream.println (x.toString());}
· encapsulate Variable -> Literal bindingEvaluateV (Binding b) {…}
Object for_Variable (Variable x) {return b.get (x);}
· other examplesinstrumentation/debugging
04/19/23 daniel jackson 19
functional visitor
basic idea· a kind of ‘map’· transforms one AST to another with nodes of different types· operation types
C’ Visitor::for_C (C)C’ C::accept (Visitor)
· inflexibility of Java’s subtyping rules a painlots of unnecessary downcasts; C’ must be Object
sample codeclass C {
D d; E e; Object accept _functional (FunctionalVisitor v) { return v.for_C (this); }
class VisitorX implements FunctionalVisitor { Object for_C (C c) { DD dd = (DD) c.d.accept_functional (this); EE ee = (EE) c.e.accept _functional (this); return someFunction (dd, ee); }
04/19/23 daniel jackson 20
imperative visitor
basic idea· mutates each element of AST· operation types
void Visitor::for_C (C)void C::accept (Visitor)
sample codeclass C {
D d; E e; void accept_imperative (ImperativeVisitor v) { v.for_C (this); }
class VisitorX implements ImperativeVisitor { void for_C (C c) { c.d.accept_imperative (this); c.e.accept_imperative (this); … return; }
04/19/23 daniel jackson 21
replacing visitor
replacing visitor· type structure of functional visitor, but mutates like imperative visitor· operation types
C’ Visitor::for_C (C)C’ C::accept (Visitor)
sample codeclass C {
D d; E e; Object accept _replacer (ReplacingVisitor v) { return v.for_C (this); }
class VisitorX implements ReplacingVisitor { Object for_C (C c) { if (…) return new C (…) else { c.d = (D) c.d.accept_replacer (this); c.e = (E) c.e.accept_replacer (this); return c; } }
04/19/23 daniel jackson 22
exploiting subclassing
basic idea· make Visitor a superclass, not an interface· dummy implementation for each element type
imperative visitor: applies the visitor to the subelementsreplacing visitor: replaces the subelements using the visitor
· each visitor implementation only overrides behaviour for some elements
examples· imperative: to print out all literals
class PrintLiteralV extends ImperativeVisitor { void for_Literal (Literal x) {stream.println (x.toString());} }
· replacing: replace all variables by dummy literalsclass InstantiateR extends ReplacingVisitor {
Object for_Variable (Variable x) {return new Literal ();} }
· then all you need is the first callexpr.accept (new FooVisitor (…));
this is a major advantage of Visitors!
04/19/23 daniel jackson 23
but … subclassing snags
can’t subclass in the element hierarchy· suppose we have
abstract class BinaryExprclass PlusExpr extends BinaryExprclass TimesExpr extends BinaryExpr
· now suppose we want a visitor that prints out binary exprs only· will this work?
class PrintBinExprV implements Visitor { for_BinaryExpr (BinaryExpr x) { stream.println (x.toString ()); } }
· no!for_BinaryExpr is never calledit’s a method associated only with the abstract class, which has no
objects
a flawed solution· default implementation of for_PlusExpr calls for_BinaryExpr
can now override for_BinaryExpr and get intended behaviour for this PrintBinExprV
· but cannot write PrintLiteralV by overriding for_Literal alonefor_PlusExpr calls for_BinaryExpr and not left.accept!