Design Patterns Reconsidered

3,159 views
3,028 views

Published on

Revisiting some popular design patterns in Java: singleton, template method, visitor.

1 Comment
21 Likes
Statistics
Notes
  • I especially like the Visitor Types where you suggest names for usual types of visitors, kinda stereotypes for visitors. I think I'll refer to this slide next time I use a visitor, telling the visitor type may help describe my intent more accurately. Cheers
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
3,159
On SlideShare
0
From Embeds
0
Number of Embeds
110
Actions
Shares
0
Downloads
450
Comments
1
Likes
21
Embeds 0
No embeds

No notes for slide

Design Patterns Reconsidered

  1. 1. Design Patterns Reconsidered Alex Miller @puredanger
  2. 2. What is a Design Pattern? “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
  3. 3. The Patterns Backlash • Copy/paste • Design by template • Cookbook / recipe approach “The Design Patterns solution is to turn the programmer into a fancy macro processor” - M. J. Dominus, “Design Patterns” Aren't
  4. 4. The Patterns Backlash • Design patterns aren’t patterns • Just workaround for missing language features “At code level, most design patterns are code smells.” - Stuart Halloway
  5. 5. The Patterns Backlash • Overuse “Beginning developers never met a pattern or an object they didn’t like. Encouraging them to experiment with patterns is like throwing gasoline on a fire.” - Jeff Atwood, Coding Horror
  6. 6. ...Reconsidered Template Visitor Method Proxy Singleton
  7. 7. Singleton
  8. 8. There can be only one... Singleton - INSTANCE + getInstance() : Singleton - Singleton() + foo() : Object
  9. 9. Classic Singleton
  10. 10. Classic Singleton public final class Singleton {
  11. 11. Classic Singleton public final class Singleton { private static Singleton INSTANCE =
  12. 12. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton();
  13. 13. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {}
  14. 14. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton instance() {
  15. 15. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton instance() { return INSTANCE;
  16. 16. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton instance() { return INSTANCE; }
  17. 17. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton instance() { return INSTANCE; } public Object read() {
  18. 18. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton instance() { return INSTANCE; } public Object read() { // nasty database call
  19. 19. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton instance() { return INSTANCE; } public Object read() { // nasty database call }
  20. 20. Classic Singleton public final class Singleton { private static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton instance() { return INSTANCE; } public Object read() { // nasty database call } }
  21. 21. Things go horribly wrong public class Victim { public void something() { Object foo = Singleton.instance().read(); // etc... } }
  22. 22. Things go horribly wrong public class Victim { public void something() { Object foo = Singleton.instance().read(); // etc... } } public class TestVictim { public void testSomething() { // Holy crap, how do I // mock the db call in Singleton? } }
  23. 23. Create Hidden Singletons Coupling!
  24. 24. Interfaces to the rescue public interface Singleton { Object read(); } public class SingletonImpl implements Singleton { public Object read() { // nasty database call return null; } }
  25. 25. Dependency injection, you’re my hero! public class Victim { private final Singleton singleton; public Victim(Singleton singleton) { this.singleton = singleton; } public void something() { Object foo = singleton.read(); // etc... } }
  26. 26. Now we can test public class TestVictim { public void testSomething() { Singleton s = new MockSingleton(); Victim victim = new Victim(s); victim.something(); // assertions } }
  27. 27. Push construction up public class Component { private final Victim victim; public Component() { victim = new Victim( new SingletonImpl() ); } }
  28. 28. Up Bubble Singletons
  29. 29. Singleton
  30. 30. What have we learned? • Interfaces and dependency injection • Reduce hidden coupling • Allow testability • Allow subclassing • Make construction and use flexible • If need only one, control by configuration • Guice • Spring
  31. 31. ...Reconsidered Template Visitor Method Proxy Singleton
  32. 32. Template Method
  33. 33. Template Method public void algorithm() { TemplateAlgorithm step1(); + algorithm() step2(); # step1() step3(); # step2() } # step3() ConcreteAlgorithm1 ConcreteAlgorithm2 # step1() # step2() # step2() # step3()
  34. 34. Spring MVC Controllers Controller (interface) AbstractController AbstractUrlViewController UrlFilenameViewController BaseCommandController AbstractCommandController AbstractFormController AbstractWizardFormController SimpleFormController CancellableFormController MultiActionController ParameterizableViewController
  35. 35. “What we’ve got here is a failure to communicate....”
  36. 36. Refactoring to steps Step1Strategy + step1() TemplateAlgorithm - Step1Strategy Step2Strategy - Step2Strategy + step2() - Step3Strategy + algorithm() Step3Strategy + step3() public void algorithm() { step1Strategy.step1(); step2Strategy.step2(); step3Strategy.step3(); }
  37. 37. Sharing context Step1Strategy + step1(Context ctx) TemplateAlgorithm - Step1Strategy Step2Strategy - Step2Strategy + step2(Context ctx) - Step3Strategy + algorithm() Step3Strategy + step3(Context ctx) public void algorithm() { Context Context context = new Context(); step1Strategy.step1(context); step2Strategy.step2(context); step3Strategy.step3(context); }
  38. 38. What have we learned? • Prefer composition to inheritance • Allows greater reuse • Communicates intent better • Easier to understand and maintain • More robust as it evolves • Inheritance is a very strong form of coupling • Especially in a single-inheritance language
  39. 39. ...Reconsidered Template Visitor Method Proxy Singleton
  40. 40. Composite hierarchy Node operation1() operation2() ConcreteNode1 CompositeNode operation1() operation1() operation2() operation2()
  41. 41. Visitor Pattern Node accept(NodeVisitor v) ConcreteNode1 CompositeNode accept(NodeVisitor v) accept(NodeVisitor v) NodeVisitor visit(ConcreteNode1 n) visit(ConcreteNode2 n) ... ConcreteVisitor1 ConcreteVisitor2 visit(ConcreteNode1 n) visit(ConcreteNode1 n) visit(ConcreteNode2 n) visit(ConcreteNode2 n) ... ...
  42. 42. N av iga tio n
  43. 43. Internal Navigation public class CompositeNode implements Visitable { private List<Node> nodes; public void accept(NodeVisitor v) { v.visit(this); for(Node n : nodes) { v.visit(n); } } }
  44. 44. Navigation oracle public class CompositeNode { private List<Node> nodes; public void accept(NodeVisitor v) { v.visit(this); List<Node> children = Navigation.getChildren(this); for(Node n : children) { n.acceptVisitor(this); } } }
  45. 45. Navigation Visitor NodeVisitor visit(ConcreteNode1 n) visit(ConcreteNode2 n) ... ConcreteVisitor1 ConcreteVisitor2 visit(ConcreteNode1 n) visit(ConcreteNode1 n) visit(ConcreteNode2 n) visit(ConcreteNode2 n) ... ... NavigationVisitor NavigationVisitor(NodeVisitor v) visit(ConcreteNode1 n) visit(ConcreteNode2 n) ...
  46. 46. Evo lutio n
  47. 47. Node accept(NodeVisitor v) ConcreteNode1 CompositeNode accept(NodeVisitor v) accept(NodeVisitor v) NewNode accept(NodeVisitor v) NodeVisitor visit(ConcreteNode1 n) visit(ConcreteNode2 n) visit(NewNode n) ... ConcreteVisitor1 ConcreteVisitor2 visit(ConcreteNode1 n) visit(ConcreteNode1 n) visit(ConcreteNode2 n) visit(ConcreteNode2 n) visit(NewNode n) visit(NewNode n) ... ...
  48. 48. NodeVisitor visit(ConcreteNode1 n) visit(ConcreteNode2 n) visit(NewNode n) ... BaseVisitor visit(ConcreteNode1 n) visit(ConcreteNode2 n) visit(NewNode n) ... ConcreteVisitor1 ConcreteVisitor2 visit(ConcreteNode1 n) visit(ConcreteNode1 n) visit(ConcreteNode2 n) visit(ConcreteNode2 n) visit(NewNode n) visit(NewNode n) ... ...
  49. 49. Visitor Types • “Collector” visitor - accumulate state • “Finder” visitor - search and return • “Event” visitor - stateless, fire events • “Transform” visitor - modify while walking • “Validation” visitor - validate and report
  50. 50. Visitor abort public class FindVisitor implements ConcreteVisitor { private final int seek; private Node match; public FindVisitor(int seek) { this.seek = seek; } public Node getMatch() { return this.match; } public void visit(ConcreteNode1 n) { if( this.match == null && n.getValue() == seek) { this.match = n;
  51. 51. Exceptions public class ComputeVisitor implements ConcreteVisitor { public void visit(ConcreteNode1 n) { try { // blah blah } catch(BadException e) { // what now? } } }
  52. 52. What have we learned? • Expression problem is tough • Abstract base classes help plan for evolution • Generics add precision and flexibility by revealing hidden coupling
  53. 53. Questions? http://tech.puredanger.com/ presentations/design- patterns-reconsidered

×