You are on page 1of 56

TS-5186 - DESIGN PATTERNS RECONSIDERED

Alex Miller Terr"c%tt" '(%%th )*)+

http://tech.p re!"#$er.c%& http://terr"c%tt".%r$

,h"t i- " De-i$# P"tter#.


Each pattern describes a problem which occurs over and over again in our environment and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. - Christopher Alexander

2008 JavaOneSM Conference | java.sun.com/javaone |

/G"#$ %0 1% r2 De-i$# P"tter#G"&&"3 4el&3 5%h#-%#3 6li--i!eCrea!ional ( s!rac! )ac!or" Buil#er )ac!or" Me!ho# *ro!o!"pe Sin%le!on S!ruc!ural (#ap!er Bri#%e Composi!e +ecora!or )aca#e )l",ei%h! *ro-" Behavioral Chain of Responsi Comman# $n!erpre!er Me#ia!or Memen!o O server S!a!e S!ra!e%" &empla!e Me!ho# 'isi!or

ili!"

2008 JavaOneSM Conference | java.sun.com/javaone |

The P"tter#- ("c7l"-h


Cop"/pas!e +esi%n " !empla!e Coo/ oo/ / recipe approach

he !esign "atterns solution is to turn the programmer into a fancy macro processor - #. $. !ominus, !esign "atterns Aren%t

2008 JavaOneSM Conference | java.sun.com/javaone |

The P"tter#- ("c7l"-h


+esi%n pa!!erns aren1! pa!!erns Jus! ,or/aroun#s for lan%ua%es missin% fea!ures

At code level, most design patterns are code smells. - &tuart 'alloway

2008 JavaOneSM Conference | java.sun.com/javaone |

The P"tter#- ("c7l"-h


Overuse

(eginning developers never met a pattern or an ob)ect they didn%t li*e. Encouraging them to experiment with patterns is li*e throwing gasoline on a fire. - $eff Atwood, Coding 'orror

2008 JavaOneSM Conference | java.sun.com/javaone |

Pr"ctic"l P"tter#...form a lan%ua%e or voca ular" ...e-pose real issues ...help us compare #esi%n choices

2008 JavaOneSM Conference | java.sun.com/javaone |

A$e#!"
Si#$let%# &empla!e Me!ho# *ro-" 'isi!or

2008 JavaOneSM Conference | java.sun.com/javaone |

There c"# 8e %#l9 %#e...

2008 JavaOneSM Conference | java.sun.com/javaone |

Si#$let%# i# C%!e - thi- i- e"-9:


public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() { } public static Singleton instance() { return INSTANCE; } public b!ect rea"() { ## nast$ "atabase call return null; } }

2008 JavaOneSM Conference | java.sun.com/javaone |

50

The# thi#$- $% h%rri8l9 ;r%#$ :'


public class Innocent%$stan"er { public voi" so&et'ing() { b!ect foo = Singleton(instance()(rea"(); ## etc((( } } public class TestInnocent%$stan"er { public voi" testSo&et'ing() { ## )a"*oo+s, -ow "o I &oc+ t'e Singleton. } }

2008 JavaOneSM Conference | java.sun.com/javaone |

55

Si#$let%# h"- i-- e6i##en couplin% &es!in% Jus! one7 $!1s a lie. 8volu!ion *ossi le memor" lea/ Su classin% $ni!iali9a!ion or#er an# #epen#encies

2008 JavaOneSM Conference | java.sun.com/javaone |

52

I#ter0"ce- t% the re-c e


public interface Singleton { b!ect rea"(); } public class SingletonI&pl i&ple&ents Singleton { public b!ect rea"() { ## nast$ "atabase call } }

2008 JavaOneSM Conference | java.sun.com/javaone |

53

Depe#!e#c9 i#<ecti%#3 9% =re &9 her%:


public class Innocent%$stan"er { private final Singleton singleton; public Innocent%$stan"er(Singleton singleton) { t'is(singleton = singleton; } public voi" so&et'ing() { b!ect foo = singleton(rea"(); ## etc((( }

2008 JavaOneSM Conference | java.sun.com/javaone |

5.

Ah3 I 0eel cle"# #%;


public class TestInnocent%$stan"er { public voi" testSo&et'ing() { Singleton s = new /oc+Singleton(); Innocent%$stan"er b$stan"er = new Innocent%$stan"er(s); b$stan"er(so&et'ing(); } ## assertions

2008 JavaOneSM Conference | java.sun.com/javaone |

50

,h"t h">e ;e le"r#e! 0r%& Si#$let%#.


$n!erfaces an# #epen#enc" injec!ion Re#uce hi##en couplin% (llo, !es!a ili!" (llo, su classin% Ma/e cons!ruc!ion an# use fle-i le $f nee# onl" one: con!rol " confi%ura!ion no! " pa!!ern ;uice Sprin% B" han# usin% injec!ion

2008 JavaOneSM Conference | java.sun.com/javaone |

52

2008 JavaOneSM Conference | java.sun.com/javaone |

53

A$e#!"
Sin%le!on Te&pl"te Meth%! *ro-" 'isi!or

2008 JavaOneSM Conference | java.sun.com/javaone |

58

Te&pl"te Meth%! ? Pl $$"8le Al$%rith&

2008 JavaOneSM Conference | java.sun.com/javaone |

54

A# ex"&ple i# the ;il! @ Spri#$ M6C


Controller (interface) AbstractController Abstract0rl1iewController 0rl2ilena&e1iewController %aseCo&&an"Controller AbstractCo&&an"Controller Abstract2or&Controller Si&ple2or&Controller Cancellable2or&Controller /ultiActionController 3ara&teri*able1iewController

2008 JavaOneSM Conference | java.sun.com/javaone |

20

Al$%rith& -pel #7i#$

2008 JavaOneSM Conference | java.sun.com/javaone |

25

1i$hti#$ %>er 9% r i#herit"#ce

2008 JavaOneSM Conference | java.sun.com/javaone |

22

Te&pl"te Meth%! h"- i-- e*oorl" #ocumen!s in!en! !o frame,or/ user *u lic vs pro!ec!e# vs a s!rac! me!ho#s )rom #ifferen! levels of inheri!ance hierarch" (l%ori!hm an# or#er of calls Relies on inheri!ance Ma/es composi!ion of func!ionali!" #ifficul! 6ar# !o main!ain an# evolve $nheri!ance hierarch" ma/e comple!el" rea/ #o,n

2008 JavaOneSM Conference | java.sun.com/javaone |

23

Repl"ce i#herit"#ce ;ith c%&p%-iti%#

2008 JavaOneSM Conference | java.sun.com/javaone |

2.

A-e c%#text cl"-- t% exp%-e -t"te

2008 JavaOneSM Conference | java.sun.com/javaone |

20

C"# cl%- re- help.


public class Te&plateAlgorit'& { private {Conte4t=5voi"} step6; public voi" a""Step6({Conte4t=5voi"} bloc+) { t'is(step6=bloc+; } public voi" co&pute() { Conte4t conte4t = new Conte4t(); step6(invo+e(conte4t); step7(invo+e(conte4t); ## &ore steps }

2008 JavaOneSM Conference | java.sun.com/javaone |

22

,h"t h">e ;e le"r#e! 0r%& Te&pl"te Meth%!.


*refer composi!ion !o inheri!ance (llo,s %rea!er reuse Communica!es in!en! e!!er 8asier !o un#ers!an# 8asier !o main!ain More ro us! as i! evolves $nheri!ance is a ver" s!ron% form of couplin% 8speciall" in a sin%le<inheri!ance lan%ua%e

2008 JavaOneSM Conference | java.sun.com/javaone |

23

A$e#!"
Sin%le!on &empla!e Me!ho# Pr%x9 'isi!or

2008 JavaOneSM Conference | java.sun.com/javaone |

28

Pr%x9 hi!e- i#-t"#ce cre"ti%#

2008 JavaOneSM Conference | java.sun.com/javaone |

24

4">e 9% r c"7e "#! e"t it t%%:


public interface Ca+e { voi" eat(); } public class C'ocolateCa+e i&ple&ents Ca+e { public C'ocolateCa+e() { #8 ba+e 8# } public voi" eat() { #8 eat 8# } } public class Ca+e3ro4$ i&ple&ents Ca+e { private Ca+e ca+e; public voi" eat() { ca+e = new C'ocolateCa+e(); ## "ela$e" construction ca+e(eat(); } }

2008 JavaOneSM Conference | java.sun.com/javaone |

30

Pr%8le&: Te!i% - t% ;rite "#! &"i#t"i# -t"tic pr%x9 cl"--epublic class Ca+e-an"ler i&ple&ents Invocation-an"ler { private Ca+e ca+e; public b!ect invo+e( b!ect pro4$9 /et'o" &et'o"9 b!ect:; args) t'rows T'rowable { if(ca+e == null) { ca+e = new C'ocolateCa+e(); } if(&et'o"(getNa&e()(e<uals(=eat>)) { ca+e(eat(); return null; } else { return &et'o"(invo+e(&et'o"9 args); }

S%l ti%# B1: D9#"&ic pr%xie2008 JavaOneSM Conference | java.sun.com/javaone | 35

Pr%8le&: Te!i% - t% ;rite "#! &"i#t"i# -t"tic pr%x9 cl"--eS%l ti%# B): AOP S%l ti%# BC: C%!e $e#er"ti%# Left as an exercise for the reader.... :)

2008 JavaOneSM Conference | java.sun.com/javaone |

32

S%&e %ther i-- e-...


*ro-" fails ,hen rel"in% on o jec! i#en!i!" *ro-" fails ,hen= Su s"s!ems communica!e usin% %eneric in!erface 8ach su s"s!em #o,ncas!s !o more specific /no,n !"pe Reall" a #esi%n pro lem.... u! i! happens +"namic pro-" si#es!eps s!a!ic !"pin% " usin% me!ho# names Coul# use Me!ho#.%e!>ame?@ u! co#e is ver" !e#ious

2008 JavaOneSM Conference | java.sun.com/javaone |

33

,h"t h">e ;e le"r#e! 0r%& Pr%x9.


*ro-" implemen!a!ions have !ra#e<offs 'er osi!" / conciseness S!a!ic !"pin% / !"pe safe!" Main!enance *erformance $#en!i!" is a !ric/" issue in OO s"s!ems Minimi9e reliance on i#en!i!"

2008 JavaOneSM Conference | java.sun.com/javaone |

3.

A$e#!"
Sin%le!on &empla!e Me!ho# *ro-" 6i-it%r

2008 JavaOneSM Conference | java.sun.com/javaone |

30

Oper"ti%#- %>er " C%&p%-ite hier"rch9

2008 JavaOneSM Conference | java.sun.com/javaone |

32

St%ppi#$ 89 0%r " >i-it

2008 JavaOneSM Conference | java.sun.com/javaone |

33

I&ple&e#ti#$ 6i-it%r
public interface 1isitable { voi" accept1isitor(1isitor visitor); } public interface 1isitor { voi" visit(ConcreteNo"e6 no"e6); ## repeat for all concrete no"es } public class ConcreteNo"e6 i&ple&ents 1isitable { public voi" accept1isitor(1isitor visitor) { visitor(visit(t'is); } } public class Concrete1isitor i&ple&ents 1isitor { ## ((( }
2008 JavaOneSM Conference | java.sun.com/javaone | 38

The Expre--i%# Pr%8le& - Philip ,"!ler3 1DD8


(## ne, cases !o a #a!a !"pe (## ne, func!ions over !he #a!a !"pe +on1! recompile ,hen a##in% ei!her cases or func!ions +on1! lose s!a!ic !"pe safe!"

2008 JavaOneSM Conference | java.sun.com/javaone |

34

Pr%8le&: ,here !%e- #">i$"ti%# c%!e li>e.


public class Co&positeNo"e i&ple&ents 1isitable { private ?ist@No"e5 no"es; public voi" accept1isitor(1isitor visitor) { visitor(visit(t'is); for(No"e no"e A no"es) { no"e(accept1isitor(visitor); } }

S%l ti%# B1: I# #%!e2008 JavaOneSM Conference | java.sun.com/javaone | .0

Pr%8le&: ,here !%e- #">i$"ti%# c%!e li>e.


public class Navigation1isitor e4ten"s %ase1isitor { private 1isitor logic1isitor; private ?in+e"?ist@. super 1isitable5 no"eBueue = new ?in+e"?ist@1isitable5(); public Navigation1isitor(1isitor logic1isitor) { t'is(logic1isitor = logic1isitor); } private voi" visitNe4t() { if(,no"eBueue(isE&pt$()) { 1isitable ne4t = (1isitable)no"eBueue(re&ove2irst(); ne4t(accept1isitor(t'is); } }

S%l ti%# B): I# #">i$"ti%# >i-it%r


2008 JavaOneSM Conference | java.sun.com/javaone | .5

Pr%8le&: ,here !%e- #">i$"ti%# c%!e li>e.


public visit(ConcreteNo"e6 no"e) { logic1isitor(visit(no"e); visitNe4t(); } public visit(Co&positeNo"e no"e) { no"eBueue(a""All(no"e(getC'il"ren()); visitNe4t(); } } ## etc

S%l ti%# B): I# #">i$"ti%# >i-it%r


2008 JavaOneSM Conference | java.sun.com/javaone | .2

C%&&%# 6i-it%r T9peACollec!orB visi!or Collec! an# accumula!e for re!urn A)in#erB visi!or Re!urn imme#ia!el" ,hen ma!ch foun# A8ven!B visi!or S!a!eless: fire even!s for su se! of no#es A&ransformB visi!or Mo#if" !he !ree ,hile ,al/in% i! *o!en!iall" #an%erous =@ A'ali#a!ionB visi!or 'erifies !he s!ruc!ure an# repor!s pro lems
2008 JavaOneSM Conference | java.sun.com/javaone | .3

Pr%8le&: Ret r#i#$ " 6"l e


public class Collector1isitor e4ten"s %ase1isitor { private final ?ist@2oo5 collecte" = new Arra$?ist@2oo5(); public ?ist@2oo5 getCollecte"() { return t'is(collecte"; } public voi" visit(ConcreteNo"e6 no"e) { if(s'oul"Collect(no"e)) { collecte"(a""(no"e); } }

S%l ti%# B1: C%llect i# >i-it%r


2008 JavaOneSM Conference | java.sun.com/javaone | ..

Pr%8le&: Ret r#i#$ " 6"l e


public interface 1isitable { @C5 voi" accept1isitor(1isitor@C5 visitor9 C conte4t); } public interface 1isitor@C5 { voi" visit(ConcreteNo"e6 no"e69 C conte4t); ## for all concrete no"es } public class ConcreteNo"e6 i&ple&ents 1isitable { public @C5 voi" accept1isitor(1isitor@C5 visitor9 C conte4t) { visitor(visit(t'is9 conte4t); } }

S%l ti%# B): Ge#eric2008 JavaOneSM Conference | java.sun.com/javaone | .0

Pr%8le&: Ret r#i#$ " 6"l e


public class Concrete1isitor i&ple&ents 1isitor@?ist@String55 { public voi" visit(ConcreteNo"e6 no"e9 ?ist@String5 conte4t) { } conte4t(a""(no"e(getStr());

## e4a&ple use ConcreteNo"e root = ((( Concrete1isitor v = new Concrete1isitor(); ?ist@String5 conte4t = new Arra$?ist@String5(); root(accept1isitor(v9 conte4t);

S%l ti%# B): Ge#eric2008 JavaOneSM Conference | java.sun.com/javaone | .2

Pr%8le&: Excepti%#public class E4ceptional1isitor e4ten"s %ase1isitor { private /$E4ception e4ception; private E4ceptional1isitor() {} public voi" c'ec+Error() t'rows /$E4ception { if(t'is(e4ception ,= null) { t'row e4ception; } } public static voi" run(No"e root) t'rows /$E4ception { E4ceptional1isitor visitor = new E4ceptional1isitor(); root(accept1isitor(visitor); c'ec+Error(); }

S%l ti%# B1: St%re i# C%#crete6i-it%r


2008 JavaOneSM Conference | java.sun.com/javaone | .3

Pr%8le&: Excepti%#public interface 1isitable { @E e4ten"s E4ception5 voi" accept1isitor(1isitor@E5 visitor) t'rows E; } public interface 1isitor@E e4ten"s E4ception5 { voi" visit(ConcreteNo"e6 no"e6) t'rows E; ## for all concrete no"es } public class ConcreteNo"e6 i&ple&ents 1isitable { @E e4ten"s E4ception5 public voi" accept1isitor(1isitor@E5 visitor) t'rows E { visitor(visit(t'is); } }

S%l ti%# B): Ge#eric2008 JavaOneSM Conference | java.sun.com/javaone | .8

C"# cl%- re- help.


Cha! if ,e #efine !he Avisi!B for each !"pe as a closure7 Collec!or visi!or D can collec! in!o local s!a!e of caller )in#er visi!or D use non<local re!urn !o a or! E re!urn 'ali#a!ion visi!or D use non<local re!urn !o a or! E re!urn Simplif" visi!ors ,i!h man" similar me!ho#s +"namicall" assem le ,i!h closures

2008 JavaOneSM Conference | java.sun.com/javaone |

.4

D9#"&ic6i-it%r 8 ilt 0r%& cl%- republic class C$na&ic1isitor i&ple&ents 1isitor { private {ConcreteNo"e6==5voi"} concreteNo"e6%loc+; private {ConcreteNo"e7==5voi"} concreteNo"e7%loc+; private {Co&positeNo"e==5voi"} co&positeNo"e%loc+; public voi" a""ConcreteNo"e6( {ConcreteNo"e6==5voi"} bloc+) { t'is(concreteNo"e6%loc+ = bloc+; } public voi" visit(ConcreteNo"e6 no"e) { if(concreteNo"e6%loc+ ,= null) { concreteNo"e6%loc+(invo+e(no"e); } } } (((

2008 JavaOneSM Conference | java.sun.com/javaone |

00

6i-it%r( il!er
public class 1isitor%uil"er { public static 1isitor%uil"er visitor() { return new 1isitor%uil"er(); } private C$na&ic1isitor visitor = new C$na&ic1isitor(); public 1isitor%uil"er 'an"leConcreteNo"e6( {ConcreteNo"e6==5voi"} bloc+) { visitor(a""ConcreteNo"e6(bloc+); return t'is;

public 1isitor buil"() { return t'is(visitor; }

2008 JavaOneSM Conference | java.sun.com/javaone |

05

A--e&8le
public class Test2in"er { public static No"e fin"/atc'(String na&e9 No"e root) { 1isitor visitor = 1isitor%uil"er(visitor() ('an"leConcreteNo"e6({ConcreteNo"e6 no"e ==5 if(no"e(getNa&e()(e<uals(na&e)) { return no"e; } }) ('an"leConcreteNo"e7({ConcreteNo"e7 no"e ==5 if(no"e(getNa&e()(e<uals(na&e)) { return no"e; } }) (buil"(); root(accept(visitor); return null; } }
2008 JavaOneSM Conference | java.sun.com/javaone | 02

,h"t h">e ;e le"r#e! 0r%& 6i-it%r.


8-pression pro lem is !ou%h !o crac/ Separa!e par!s of !he #esi%n !ha! chan%e a! #ifferen! ra!es ;enerics a## precision an# fle-i ili!" " e-posin% hi##en couplin% Closures provi#e some in!eres!in% ne, possi ili!ies

2008 JavaOneSM Conference | java.sun.com/javaone |

03

De-i$# Pri#cipleFse in!erfaces an# #epen#enc" injec!ion !o re#uce couplin% )avor composi!ion over inheri!ance Separa!e lo%ic !ha! ,ill evolve a! #ifferen! ra!es Rel" on o jec! i#en!i!" as li!!le as possi le Gevera%e s!a!ic !"pin% an# %enerics

2008 JavaOneSM Conference | java.sun.com/javaone |

0.

S &&"r9
+esi%n pa!!erns are a valua le !ool !o #escri e real pro%rammin% pro lems. Solu!ions !o all #esi%n pro lems are con!e-!ual ?#epen#en! on lan%ua%e: !he co#e ase: an# !he #evelopers !hemselves@. Fse #esi%n pa!!erns as a s!ar!in% !o poin! !o #iscuss al!erna!ives. +on1! s!op a! an e-ample from a oo/ or a lo% or even a JavaOne even! presen!a!ion. =@ 8-perimen! !o fin# ,ha! ,ill ,or/ es! for "ouH
2008 JavaOneSM Conference | java.sun.com/javaone | 00

De-i$# P"tter#- Rec%#-i!ere! Alex Miller


http://tech.p re!"#$er.c%&/pre-e#t"ti%#-

2008 JavaOneSM Conference | java.sun.com/javaone |

02