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