Designing Object Oriented Software - lecture slides 2013

2,879 views

Published on

Slides from the course Designing Object Oriented Software (spring 2013). The course focuses on the principles, patterns and practices behind sound software designs.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,879
On SlideShare
0
From Embeds
0
Number of Embeds
179
Actions
Shares
0
Downloads
96
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Designing Object Oriented Software - lecture slides 2013

  1. 1. Designing Object-Oriented Software Jouni Smed 2013
  2. 2. Course Syllabus l Credits: 5 cp l Teaching methods: lectures, voluntary exercise work ¡ Thursdays 10–12, Auditorium Alpha ¡ from March 14 to April 25 l Assessment: examination only l Course web page: http://bit.ly/doos2013
  3. 3. Examinations l Electronic examination ¡ opens May 6, 2013 ¡ closes September 30, 2013 l You can take the examination at most three (3) times l For instructions and examination time reservations, see https://tenttis.utu.fi/
  4. 4. Voluntary Exercise Work l Four group sessions ¡ in April (the exact dates are to be announced) ¡ organized by Antero Järvi and Aki Salmi l Hands-on exercises in software design l Active participation can give you extra points for the assessment
  5. 5. Assessment l Examination: 18 points l Voluntary exercise work: 2 bonus points l Grading (based on 18 points): ¡ points: ¡ points: ¡ points: ¡ points: ¡ points: [9, 10] ⇒ grade: 1 (10, 12] ⇒ grade: 2 (12, 14] ⇒ grade: 3 (14, 16] ⇒ grade: 4 (16, 20] ⇒ grade: 5
  6. 6. Textbook for the Course l Martin, Robert C., and Martin, Micah: Agile Principles, Patterns and Practices in C#, Prentice-Hall, 2006, ISBN: 0-13-185725-8 Or the older version: l Martin, Robert C.: Agile Software Development: Principles, Patterns, and Practices, Prentice-Hall, 2003, ISBN: 0-13-597444-5
  7. 7. Outline of the Course Lecture Topics 1. March 14 Introduction. Models for software production. Design smells. 2. March 21 Design principles: SRP, OCP, LSP. 3. March 28 Design principles: DIP, ISP. Design patterns. 4. April 4 Design patterns. 5. April 11 Package design principles: REP, CRP, CCP, ADP, SDP, SAP. 6. April 18 Design patterns. 7. April 25 Design patterns. Conclusions Note
  8. 8. What is Design? l Design is a creative process ¡ there is no algorithm l Designing software systems is a creative process, where the designer has a goal given by the customer
  9. 9. What is Object Oriented? l Object oriented means a way of dividing a complex whole into independent, co-operating components l The challenge is to find a natural division ¡ “natural” can mean different things in different situations
  10. 10. What is a System? l A system is a task (small or large) automatized by software ¡ the scope is normally defined by the customer l If the system is not defined well, the software design process will fail ¡ the system will not be helpful ¡ the system will not be used the endusers nor will help their work
  11. 11. A SHORT HISTORY OF SOFTWARE DESIGN
  12. 12. Programming in the 1940s and 1950s l  Programming = instructing the machine operations ¡ machine language or assembler ¡ machine-oriented programming l  Far from the way programmers (humans) think l  The problem domain remained close to the machine world ¡ making calculations, sorting data etc. l  Main goals of design ¡ enable the programmer to write the software ¡ focus on the design of algorithms and data structures. l  Implementing the design was difficult
  13. 13. Programming in the 1960s and 1970s l  ‘High-level’ programming languages ¡ Algol, Fortran, Pascal, Ada, C, … ¡ problem-oriented programming l  Innovations ¡ reducing machine dependency: portability ¡ managing complex and large problems: structured programming, modular programming and information hiding l  Main goals of design ¡ enable an automatic transformation of an analysis model to a program structure ¡ managing the work of many simultaneous programmers ¡ keeping the system maintainable
  14. 14. Programming in the 1960s and 1970s (cont’d) l  Programming comprised ¡ creating and manipulating complex data structures and algorithms ¡ realizing subroutines ¡ dealing with the physical organization of the software l  The problem domain took a big leap towards the real world ¡ commercial information systems, traffic, science… l  This was the era of waterfall way of building systems, which led to the so-called software crisis
  15. 15. Programming in the 1980s and 1990s l  Rise of the object-oriented (OO) paradigm ¡  real-world concepts are directly supported with programming language constructs (e.g. classes) l  Detailed design ¡  how to implement an analysis model with OO mechanisms? ¡  class-level reuse, specifying the programming task for a programmer, understandability and maintainability of the source code l  Architecture design ¡  how to create, describe and manage the big picture of a system ¡  maintainability of the system, manageability during design (multiple team development), handling non-functional properties of the system, high-level reuse, adaptability of the system… l  Programming was still seen as realizing the design
  16. 16. Programming Now l  The new software crisis: the bloat of design work ¡  expensive ¡  opposes maintainability and adaptability l  Iterative way of building large systems changes the role of design ¡  the design is created piece by piece as the understanding of the problem grows l  Programming and detailed design are unifying ¡  high-level constructs allow to express the design in the code ¡  design patterns allow even to express the architecture design l  The role of the programmer is rising ¡  operates at the design level ¡  understands the profound object-oriented principles
  17. 17. Three Perspectives on Software Development l  Conceptual ¡  represents the concepts in the problem-domain ¡  objects defined in the terms of responsibilities l  Specification Design ¡  focuses on the software at the level of interfaces (not the implementation) ¡  how the modules are connected l  Implementation ¡  looks inside the modules, the code ¡  probably the most often used perspective (should not be) ¡  objects are seen as encapsulating data and providing access to services Programming
  18. 18. Traditional Engineering… l The design is expressed in the blueprints l Engineers try to make absolutely sure that ¡ the design is correct ¡ requirements are met ¡ the product will function as specified l Why? ¡ building the product is expensive ¡ construction cannot be undone (or it is expensive to do so) l Construction is done by different people → The blueprints must contain all information needed for construction
  19. 19. …and Software Engineering l Source code is the blueprints l Compiler does the actual construction work l Since construction is virtually costless it can be redone over and over again! ¡ traditional engineering ≠ software engineering
  20. 20. What Makes Software Systems Complicated? l  The problem being solved ¡ finding and understanding the requirements l  The software itself ¡ managing and understanding the software ¡ finding a solution that meet the requirements l  The software organization ¡ managing the employees working on the same system l  The software industry ¡ constantly changing environments ¡ market situation ¡ platform technologies
  21. 21. Programming vs. Design? l  Complexity and volatile requirements → iterative approach with feedback l  Construction is cheap ¡ no need to speculate by building models, prototypes, simulations l  Iteration can cover analysis-design-implementationtesting phases → the act of design in software engineering l  Programming is ¡ constructing the software (i.e. programming) ¡ designing the software l  Not designing the program but programming the design
  22. 22. MODELS FOR SOFTWARE PRODUCTION
  23. 23. The Waterfall Model Requirements Design Implementation Verification Maintenance
  24. 24. picture source: Wikimedia Commons The Spiral Model
  25. 25. Agile Software Development l Values good old engineering skills over the exact process management of business people l Reduces the overhead from process management to minimum l Requires that the developers can self-organize
  26. 26. The Agile Manifesto We are uncovering better ways of developing software by doing it and helping others do it. Through this work we have come to value: Individuals and interactions over processes and tools Working software over comprehensive documentation Customer collaboration over contract negotiation Responding to change over following a plan That is, while there is value in the items on the right, we value the items on the left more
  27. 27. Agile Methods l Refers to a family of methods that agree with the values given in the Agile Manifesto ¡ Extreme programming (XP) ¡ Scrum ¡ DSDM ¡ Crystal
  28. 28. TESTING AND REFACTORING
  29. 29. Development l Planning l Testing l Refactoring
  30. 30. Planning l  Initial exploration ¡  developers and customers identify all significant user stories ¡  estimate the cost of the stories l  splitting and merging l  velocity ← cost and priority of a story l  Release planning ¡  a crude selection of stories to be implemented in the first release l  business decisions ¡  developers and customers agree on a date for the first release l  typically 2–4 months in the future l  Iteration planning ¡  developers and customers agree on the iteration length l  typically 2 weeks
  31. 31. Iteration l  Start: ¡  developers and customers get together ¡  customers choose stories to be implemented l  no more than velocity allows l  cannot be changed once the iteration has begun ¡  task planning: developers break the stories down to development tasks (implementable in 4–16 h) l  Halfway point: ¡  the team meats and assesses the progress so far l  End: ¡  iteration ends on the specified date (regardless whether the stories are done) ¡  developers demonstrate the current running executable to the customers for evaluation ¡  the velocity is updated
  32. 32. Testing l  Writing unit tests is an act of ¡ design ¡ documentation ¡ verification l  Test driven development: design tests before you design the program l  Effects ¡ backstop for further development: add and change without fear of breaking the existing software ¡ different point of view: write from the vantage point of a caller of the program → interface and function of a program ¡ forces to decouple the software ¡ documentation: how to call a function? check the test!
  33. 33. Testing (cont’d) l Unit tests ¡ white-box tests that verify individual mechanisms ¡ do not verify that the system works as a whole ¡ documents the internals of a system l Acceptance tests ¡ black-box tests that verify that customer requirements are being met ¡ written by people (customers, QA) who do not know the internal mechanisms of the system ¡ documents the features of a system
  34. 34. Refactoring l Practical definition: altering the source code systematically to improve its design ¡ easier to understand ¡ cheaper to modify ¡ does not change its observable behavior ¡ the goal is not better performance
  35. 35. Benefits of Refactoring l Improves the design of the software ¡ creates the design in the existing code ¡ adjusts the design piece by piece to changing functionality l Helps in finding bugs ¡ clarifies the purpose of the code to a point where you simply cannot avoid seeing the bugs l Helps in programming faster ¡ without refactoring you start faster but lose speed after a while
  36. 36. When to Refactor? l  Rule of three ¡  first time: just do it ¡  second time: you may duplicate ¡  third time: refactor l  Refactor when you add functionality ¡  refactor the code that is going to change before you make the change to understand it deeply ¡  if the change does not fit in easily, refactor the design to enable smooth addition of the new feature l  Refactor when you need to fix a bug ¡  a bug indicates that the code is not easy to understand l  Refactor in a code review ¡  if you are going through the code, why not go through the design as well l  Refactor all the time ¡  it is an integral part of designing and programming
  37. 37. DESIGN SMELLS
  38. 38. Design Smells l A design smell is a sign that the design process is out of control l A serious case can result in missed deadlines and increasing costs l This can be avoided by ¡ incremental design ¡ constant refactoring at many levels
  39. 39. What Goes Wrong with Software? l You start with a clear picture in your mind l Then something goes wrong ¡ changes and additions are harder and harder to make ¡ you are forced to let go of the original design ideas ¡ eventually even the simplest changes terrify you because of rippling unexpected effects, and you must redesign the whole software. l You started with good intentions, so what went wrong?
  40. 40. Design Smells a.k.a Seven Deadly Sins a.k.a. Symptoms of Poor Design 1.  2.  3.  4.  5.  6.  7.  Rigidity Fragility Immobility Viscosity Needless complexity Needless repetition Opacity
  41. 41. Rigidity l The design is hard to change ¡ changes propagate via dependencies to other modules ¡ no continuity in the code l Management reluctance to change anything becomes the policy l Telltale sign: ‘Huh, it was a lot more complicated than I thought.’
  42. 42. Fragility l The design is easy to break ¡ changes cause cascading effects to many places ¡ the code breaks in unexpected places that have no conceptual relationship with the changed area ¡ fixing the problems causes new problems l Telltale signs ¡ some modules are constantly on the bug list ¡ time is used finding bugs, not fixing them ¡ programmers are reluctant to change anything in the code
  43. 43. Immobility l The design is hard to reuse ¡ the code is so tangled that it is impossible to reuse anything l Telltale sign: a module could be reused but the effort and risk of separating it from the original environment is too high
  44. 44. Viscosity l  Viscosity of the software ¡ changes or additions are easier to implement by doing the wrong thing l  Viscosity of the environment ¡ the development environment is slow and inefficient ¡ high compile times, long feedback time in testing, laborious integration in a multi-team project l  Telltale signs ¡ when a change is needed, you are tempted to hack rather than to preserve the original design ¡ you are reluctant to execute a fast feedback loop and instead tend to code larger pieces
  45. 45. Needless Complexity l Design contains elements that are not currently useful ¡ too much anticipation of future needs ¡ developers try to protect themselves against probable future changes ¡ agile principles state that you should never anticipate future needs l Extra complexity is needed only when designing an application framework or customizable component l Telltale sign: investing in uncertainty
  46. 46. Needless Repetition l The same code appears over and over again, in slightly different forms ¡ developers are missing an abstraction ¡ bugs found in a repeating unit have to be fixed in every repetition l Telltale sign: overuse of copy-andpaste
  47. 47. Opacity l The tendency of a module to become more difficult to understand ¡ every module gets more opaque over time ¡ a constant effort is needed to keep the code readable l easy to understand l communicates its design l Telltale sign: you are reluctant to fix somebody else’s code – or even your own! E E E E E E E E E E E E E
  48. 48. DESIGN PRINCIPLES
  49. 49. How to Avoid the Design Smells l There are five central design priciples that guide towards good design and good coding practices l If the right design principles are well understood, they will lead the design in the right direction without the need for extensive planning
  50. 50. The Five Principles 1.  2.  3.  4.  5.  Single-Responsibility Principle Open–Closed Principle Liskov Substitution Principle Depency-Inversion Principle Interface-Segregation Principle
  51. 51. SRP: The Single-Responsibility Principle A class should have only one reason to change. l Cohesion: how good a reason the elements of a module have to be in the same module l Cohesion and SRP: the forces that cause the module to change
  52. 52. Responsibility l  Rationale behind SRP ¡ changes in requirements → changes in class responsibilities ¡ a ‘cohesive’ responsibility is a single axis of chance → a class should have only one responsibility ¡ responsibility = a reason to change l  Violation of SRP causes spurious transitive dependencies between modules that are hard to anticipate → fragility l  Separating the responsibilities into interfaces decouples them as far as rest of the application is concerned
  53. 53. SRP Example: Rectangle More than one responsibility Computational Geometry Application Rectangle +draw() +area(): double Graphical Application Separated responsibilities Computational Geometry Application GUI Graphical Application Geometric Rectangle +area(): double Rectangle +draw() GUI
  54. 54. SRP Example: Modem 1(2) public interface Modem { public void dial(String pno); public hangup(); public void send(char c); public char receive(); }
  55. 55. SRP Example: Modem 2(2) public interface Connection { public void dial(String pno); public hangup(); } public interface DataChannel { public void send(char c); public char receive(); }
  56. 56. OCP: The Open–Closed Principle Software entities should be open for extension, but closed for modification. – Bertrand Meyer l  ‘Open for extension’: the behaviour of a module can be extended with new behaviours to satisfy the changing requirements l  ‘Closed for modification’: extending the module must not result in changes to the source or even binary code of the module
  57. 57. OCP (cont’d) l  Reduces rigidity ¡ a change does not cause a cascade of related changes in dependent modules l  Changing the module without changing its source code – a contradiction?! l  How to avoid dependency on a concrete class? ¡ abstraction ¡ dynamic binding
  58. 58. Basic OCP Designs STRATEGY Client «interface» Client Interface TEMPLATE METHOD Policy +policyFunction() -serviceFunction() Server Implementation -serviceFunction()
  59. 59. Strategic Closure l  Conforming to the OCP is expensive, since it can incur needless complexity l  All changes cannot be anticipated ¡ apply OCP to the most obvious changes l  Otherwise: ‘Fool me once, shame on you. Fool me twice, shame on me.’ ¡ once a change has occurred, it is more probable that a similar kind of change will occur later ¡ apply OCP when it is needed for the first time l  A good strategy: stimulate early changes ¡ fast iterations ¡ constant feedback
  60. 60. OCP: Simple Heuristics l Make all object-data private ¡ changes to public data are always at risk to ‘open’ the module ¡ all clients of a module with public data members are open to one misbehaving module ¡ errors can be difficult to find and fixes may cause errors elsewhere l No global variables ¡ it is impossible to close a module against a global variable
  61. 61. LSP: The Liskov Substitution Principle Subtypes must be substitutable for their base types. – Barbara Liskov l  Functions that refer to base classes must be able to use objects of both existing and future derived classes without knowing it l  Inheritance must be used in a way that any property proved about supertype objects also holds for the subtype objects
  62. 62. LSP and OCP l  LSP is motived by OCP (at least partly) ¡ abstraction and polymorphism allows us to achieve OCP, but how to use them? ¡ key mechanism in statically typed languages: inheritance l  LSP restricts the use of inheritance in a way that OCP holds l  LSP addresses the questions of ¡ what are the inheritance hierarchies that give designs conforming to OCP ¡ what are the common mistakes we make with inheritance regarding OCP? l  Violation of LSP is a latent violation of OCP
  63. 63. Example: Inheritance Has Its Limits public abstract class Bird { public abstract void fly(); } public class Parrot extends Bird { public void fly() { /* implementation */ } public void speak() { /* implementation */ } } public class Penguin extends Bird { public void fly() { throw new UnsupportedOperationException(); } }
  64. 64. Example (cont’d) public static void playWith(Bird bird) { bird.fly(); } Parrot myPet; playWith(myPet); // myPet "is-a" bird and can fly() Penguin myOtherPet; playWith(myOtherPet); // myOtherPet "is-a" bird // and cannot fly()?!
  65. 65. Example (cont’d) l  What went wrong? ¡ we did not model ‘Penguins cannot fly’ ¡ we modelled ‘Penguins may fly, but if they try it is an error’ l  The design fails LSP ¡ a property assumed by the client about the base type does not hold for the subtype ¡ Penguin is not a subtype of Bird l  Subtypes must respect what the client of the base class can reasonably expect about the base class ¡ but how can we anticipate what some client will expect?
  66. 66. Design by Contract l  A class declares its behaviour ¡ requirements (preconditions) that must be fulfilled ¡ promises (postconditions) that will hold afterwards l  This forms a contract between the class and a client using its services ¡ tells explicitly what the client may expect l  B. Mayer (1988): When redefining a method in a derived (or inherited) class ¡ the precondition can be replaced only by a weaker one ¡ the postcondition can be replaced only by a stronger one l  A derived class should require no more and provide no less than the base class
  67. 67. LSP: Simple Heuristic l  Telltale signs of LSP violation: ¡ degenerate functions in derived classes (i.e. overriding a base-class method with a method that does nothing) ¡ throwing exceptions from derived classes l  Solution 1: inverse the inheritance relation ¡ if the base class has only additional behaviour l  Solution 2: extract common a base class ¡ if both initial and derived classes have different behaviors ¡ penguins → Bird, FlyingBird, Penguin l  Sometimes it is not possible to edit the base class ¡ example: Java Collections Hierarchy
  68. 68. Example: java.util.Collection public interface Collection<E> extends Iterable<E> { //-- Basic operations public int size(); public boolean isEmpty(); public boolean contains(Object o); public boolean add(E o); // public boolean remove(Object o); // public Iterator<E> iterator(); //-- Collection operations public boolean containsAll(Collection<?> c); public boolean addAll(Collection<? extends E> c); // public boolean removeAll(Collection<?> c); // public boolean retainAll(Collection<?> c); // public void clear(); // //-- Array operations public Object[] toArray(); public <T> T[] toArray(T[] a); } Optional Optional Optional Optional Optional Optional
  69. 69. DIP: The Dependency-Inversion Principle High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions. – Robert Martin
  70. 70. DIP (cont’d) l  Modules with detailed implementations are not depended upon, but depend themselves upon abstractions l  High-level modules contain the important business model of the application, the policy ¡ independent of details ¡ should be the focus of reuse ¡ greatest benefits are achievable here l  Results from the rigorous use of LSP and OCP ¡ OCP states the goal ¡ LSP enables it ¡ DIP shows the mechanism to achieve the goal
  71. 71. Example: Naïve Layering Scheme Policy Layer Mechanism Layer Utility Layer
  72. 72. Example: Inverted Layers Policy Policy Layer «interface» Policy Service Interface Mechanism Mechanism Layer «interface» Mechanism Service Interface Utility Utility Layer
  73. 73. Design to an Interface l  Rationale ¡  abstract classes/interfaces tend to change less frequently ¡  abstractions are ‘hinge points’ where it is easier to extend/modify ¡  no need to modify classes/interfaces that represent the abstraction l  All relationships should terminate to an abstract class or interface ¡  no variable should refer to a concrete class l  use inheritance to avoid direct bindings to concrete classes ¡  no class should derive from a concrete class l  concrete classes tend to be volatile ¡  no method should override an implemented method of any of its base classes l  Exceptions ¡  some classes are very unlikely to change → a little benefit in inserting an abstraction layer l  you can depend on a concrete class that is not volatile (e.g. String class) ¡  a module that creates objects automatically depends on them
  74. 74. ISP: The Interface-Segregation Principle Clients should not be forced to depend upon methods that they do not use. l Many client-specific interfaces are better than one general purpose interface ¡ no ‘fat’ interfaces ¡ no non-cohesive interfaces l Related to SRP
  75. 75. Fat Interfaces l  Fat interface = general purpose interface ≠ client-specific interface ¡ can cause bizarre couplings between its clients ¡ when one client forces a change, all other clients are affected l  Break a fat interface into many separate interfaces ¡ targeted to a single client or a group of clients ¡ clients depend only on the methods they use (and not on other clients’ needs) ¡ impact of changes to one interface are not as big ¡ probability of a change reduces ¡ no interface pollution
  76. 76. Example: Door and Timer public class Door { public void lock() { /* implementation */ } public void unlock() { /* implementation */ } public boolean isOpen() { /* implementation */ } } public class Timer { public void register(int timeout, TimerClient client) { /* implementation */ } } public interface TimerClient { public void timeout(); }
  77. 77. Example: Timer Client at Top of Hierarchy Timer 0..* «interface» TimerClient +timeout() Door TimedDoor
  78. 78. Example: Separation Through Delegation Timer 0..* «interface» TimerClient Door +timeout() DoorTimer Adapter +timeout() TimedDoor +doorTimeout() «creates» «registers»
  79. 79. Example: Separation Through Multiple Inheritence Timer 0..* «interface» TimerClient +timeout() TimedDoor +timeout() «registers» Door
  80. 80. Role-Based Interface Design l  Interfaces are designed from the viewpoint of the service user, not the service provider ¡ clients own the interfaces l  Interfaces should represent roles that clients take when using the services of a class or component l  Classes implement many interfaces, interfaces are implemented by many classes ¡ example: flying birds (as well as bats) implement interface FlyingCreature, but penguins do not l  Version control by adding new interfaces for clients requiring new services → less viscosity
  81. 81. Five Principles (revisited) 1.  2.  3.  4.  5.  Single-Responsibility Principle Open–Closed Principle Liskov Substitution Principle Depency-Inversion Principle Interface-Segregation Principle
  82. 82. DESIGN PATTERNS
  83. 83. Design Patterns: Background l  Architectural design patterns ¡ Christopher Alexander et al.: A Pattern Language, 1977 ¡ Christopher Alexander: The Timeless Way of Building, 1979 l  World consists of repeating instances of various patterns ¡ a pattern is (possibly hidden) design know-how that should be made explicit ¡ ‘a quality without name’: not measurable but recognizable l  User-centred design ¡ capture the quality in a pattern language ¡ inhabitants should design their own buildings together with a professional using the patterns
  84. 84. Alexander’s Patterns l  What do high-quality contructs have in common? l  Structures cannot be separated from the problems they are solving l  Similarities in the solution structures → a pattern l  Each pattern defines subproblems solved by other smaller patterns l  A pattern is a rule that expresses a relation between ¡ a context ¡ a problem and ¡ a solution
  85. 85. Alexander’s Patterns (cont’d) ‘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.’ – C. Alexander, The Timeless Way of Building, 1979
  86. 86. Software Design Patterns ‘[Patterns] are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.’ ‘A design pattern names, abstracts, and identifies the key aspects of a common design structure that make it useful for creating a reusable objectoriented design.’ – E. Gamma (1995):
  87. 87. Software Design Patterns (cont’d) l  Reusable solutions to general design problems l  Represent solutions to problems that arise when developing software within a particular context ¡ design pattern = problem–solution pair in a context ¡ basic steps remain the same but the exact way of applying a pattern is always different l  Capture well-proven experience in software development ¡ static and dynamic structure ¡ collaboration among the key participants l  Facilitate the reuse of successful software architectures and designs
  88. 88. Definition of a Design Pattern A general solution to a frequently occurring architecture/design problem in a context. l  l  l  l  l  Not specific to any language, environment etc. Described as a semiformal document Addresses a common problem Can be applied at architecture or detailed design level Appears in a context that defines certain requirements or forces
  89. 89. Motivation l  Reusing the solutions ¡  learn from other good designs, not your own mistakes ¡  architectural building blocks for new designs l  Estabishing a common terminology ¡  communication and teamwork ¡  documenting the system l  Giving a higher-level perspective on the problem and the process of design and object orientation ¡  articulate the design rationale ¡  make hidden design knowledge explicit and available ¡  name and explicate higher-level structures which are not directly supported by a programming language
  90. 90. The ‘Gang-of-Four’ Design Patterns l  Gamma et al. describe and document 23 design patterns using a semi-formal procedure l  GoF patterns are ¡ not very problem-specific ¡ small and low-level patterns ¡ focusing on flexibility and reuse through decoupling of classes l  Underlying principles ¡ program to an interface, not to an implementation ¡ favour composition over inheritance ¡ find what varies and encapsulate it
  91. 91. Describing a Design Pattern Name Increases the design vocabulary Intent The purpose of the pattern Problem Description of the problem and its context, presumptions, example Solution How the pattern provides a solution to the problem in the context in which it shows up Participants The entities involved in the pattern Consequences Benefits and drawbacks of applying the design pattern; investigates the forces at play in the pattern Implementation Different choices in the implementation of the design pattern, possibly language-dependent
  92. 92. Benefits of Design Patterns l Patterns improve developer communication l Patterns enhance understanding by documenting the architecture of a system l Patterns enable large-scale reuse of software architectures l Patterns do not provide solutions, they inspire solutions!
  93. 93. Design Patterns – the Flip Side l  Patterns are not without potential problems ¡  design fragmentation: more classes, more complicated dependencies ¡  overkilling problems ¡  excessive dynamic binding, potentional performance problem ¡  ‘object schitzophrenia’, splitting objects ¡  wrong design pattern can cause much harm l  Integrating patterns into a software development process is a human-intensive activity ¡  not a piece of ready-to-use code ¡  can be implemented in many ways ¡  not a general remedy to improve your system l  Patterns can be deceptively simple ¡  condensed and abstracted experience and wisdom l  Patterns are not written in stone! ¡  reject or modify them to suit your needs
  94. 94. Design Patterns: Set 1 l COMMAND and ACTIVE OBJECT l TEMPLATE METHOD and STRATEGY l FACADE and MEDIATOR l SINGLETON and MONOSTATE l NULL OBJECT
  95. 95. COMMAND «interface» Command Sensor +do() RelayOn Command MotorOn Command RelayOff Command ClutchOn Command MotorOff Command ClutchOff Command
  96. 96. COMMAND (cont’d) l  A function object; a method wrapped in an object l  The method can be passed to other methods or objects as a parameter l  Decouples the object that invokes the operation from the one performing it ¡  physical and temporal decoupling l  Cf. java.lang.Runnable «interface» Command +do() +undo()
  97. 97. ACTIVE OBJECT: Example public interface Command { public void execute(); } public class ActiveObjectEngine { private List<Command> commands = new LinkedList<Command>(); public void addCommand(Command c) { commands.add(c); } } public void run() { while (!commands.isEmpty()) { Command c = commands.getFirst(); commands.remove(c); c.execute(); } }
  98. 98. TEMPLATE METHOD and STRATEGY Application +run() #init() #idle() #cleanup() Application Runner «interface» Application +run() +init() +idle() +cleanup() Implementation #init() #idle() #cleanup() Strategy1 Strategy2 Strategy3
  99. 99. TEMPLATE METHOD and STRATEGY (cont’d) l  Defines the skeleton of an algorithm ¡  some steps are deferred to subclasses ¡  subclasses redefine the steps without changing the overall structure l  Used prominently in frameworks l  Cf. java.applet.Applet, javax.swing.JApplet l  Defines a family of algorithms ¡  encapsulated, interchangeable ¡  algorithm can vary independently from clients that use it l  Identify the protocol that provides the level of abstraction, control, and interchangeability for the client → abstract base class l  All conditional code → concrete derived classes
  100. 100. FACADE Client Facade +operation1() +operation2() … Database Connection Statement Driver Manager ResultSet Prepared Statement SQL Exception
  101. 101. FACADE (cont’d) l A unified interface to a set of interfaces in a subsystem ¡ encapsulates a complex subsystem within a single interface object ¡ makes the subsystem easier to use l Decouples the subsystem from its clients ¡ if it is the only access point, it limits the features and flexibility l Imposes a policy ‘from above’ ¡ everyone uses the facade instead the subsystem ¡ visible and constraining
  102. 102. MEDIATOR l  Imposes a policy ‘from below’ ¡  hidden and unconstraining l  Promotes loose coupling JList JTextField ¡  objects do not have to refer to one another ¡  simplifies communication l  Problem: monolithism l  Example: QuickEntryMediator ¡  binds text-entry field to a list ¡  when text is entered, the first element matching in the list is highlighted QuickEntry Mediator «anonymous» Document Listener
  103. 103. SINGLETON: Example public class Singleton { private static Singleton theInstance = null; private Singleton() { /* nothing */ } } public static Singleton create() { if (theInstance == null) theInstance = new Singleton(); return theInstance; }
  104. 104. MONOSTATE: Example public class Monostate<T> { private static T itsValue = null; public Monostate() { /* nothing */ } } public void set(T value) { itsValue = value; } public T get() { return itsValue; }
  105. 105. Comparison l  SINGLETON ¡ applicable to any class ¡ lazy evaluation: if not used, not created ¡ not inherited: a derived class is not singleton ¡ can be created through derivation ¡ non-transparent: the user knows… ¡ cf. java.lang.Integer.MAX_VALUE, java.util.Collections.EMPTY_SET l  MONOSTATE ¡ inherited: a derived class is monostate ¡ polymorphism: methods can be overridden ¡ normal class cannot be converted through derivation ¡ transparent: the user does not need to know…
  106. 106. NULL OBJECT Application «creates» «creates» «interface» Employee NullEmployee Employee Implementation
  107. 107. NULL OBJECT: Example public interface Employee { public boolean isTimeToPay(Date payDate); public void pay(); public static final Employee NULL = new Employee() { public boolean isTimeToPay(Date payDate) { return false; } public void pay() { /* nothing */ } }; }
  108. 108. PACKAGE DESIGN
  109. 109. Six Principles of Package Design 1.  Reuse–Release Equivalence Principle 2.  Common-Reuse Principle 3.  Common-Closure Principle 4.  Acyclic-Dependencies Principle 5.  Stable-Dependencies Principle 6.  Stable-Abstractions Principle Cohesion Coupling
  110. 110. Package Cohesion and Coupling l  Cohesion within a package ¡ ‘bottom–up’ view of partitioning ¡ classes in a packages must have a good reason to be there ¡ classes belong together according to some criteria l political factors l dependencies between the packages l package responsibilities l  Coupling between packages ¡ dependencies accross package boundaries ¡ relationships between packages l technical l political l volatile
  111. 111. REP: The Reuse–Release Equivalence Principle The granule of reuse is the granule of release. l  Anything we reuse must also be released and tracked l  Package author should guarantee ¡  maintanance ¡  notifications on future changes ¡  option for a user to refuse any new versions ¡  support for old versions for a time
  112. 112. REP (cont’d) l Primary political issues ¡ software must be partitioned so that humans find it convenient l Reusable package must contain reusable classes ¡ either all the classes in a package are reusable or none of them are l Reusable by the same audience
  113. 113. CRP: The Common-Reuse Principle The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.
  114. 114. CRP (cont’d) l  If one class in a package uses another package, there is a dependency between the packages ¡ whenever the used package is released, the using package must be revalidated and re-released ¡ when you depend on a package, you depend on every class in that package! l  Classes that are tightly bound with class relationships should be in the same package ¡ these classes typically have tight coupling ¡ example: container class and its iterators l  The classes in the same package should be inseparable – impossible to reuse one without another
  115. 115. CCP: The Common-Closure Principle The classes in a package should be closed together against the same kind of changes. A change that affects a closed package affects all the classes in that package and no other packages.
  116. 116. CCP (cont’d) l  SRP restated for packages ¡ a package should not have multiple reason to change l  Maintainability often more important than reusability ¡ changes should occur all in one package ¡ minimizes workload related releasing, revalidating and redistributing l  Closely related to OCP ¡ strategic closure: close against types of changes that are probable ¡ CCP guides to group together classes that are open to the same type of change
  117. 117. Recap: Cohesion l Reuse–Release Equivalence Principle ¡ partition so that it is convenient to the users of the package l Common-Reuse Principle ¡ partition so that the classes are tightly bound together l Common-Closure Principle ¡ partition so that a change is limited to one package only
  118. 118. ADP: The Acyclic-Dependencies Principle Allow no cycles in the package dependency graph. l  Without cycles it is easy to compile, test and release ‘bottom-up’ when building the whole software l  The packages in a cycle will become de facto a single package ¡  compile-times increase ¡  testing becomes difficult since a complete build is needed to test a single package ¡  developers can step over one another since they must be using exactly the same release of each other’s packages
  119. 119. The ‘Morning-After Syndrome’ l  Developers are modifying the same source files trying to make it work with the latest changes somebody else did → no stable version l  Solution #1: the weekly build ¡ developers work alone most of the week and integrate on Friday ¡ works on medium-sized projects ¡ for bigger projects, the iteration gets longer (monthly build?) → rapid feedback is lost l  Solution #2: ¡ partition the development environment into releasable packages ¡ ensure ADP
  120. 120. Release-Control l  Partition the development environment into releasable packages ¡  package = unit of work ¡  developer modifies the package privately ¡  developer releases the working package ¡  everyone else uses the released package while the developer can continue modifying it privately for the next release l  No developer is at the mercy of the others ¡  everyone works independently on their own packages ¡  everyone can decide independently when to adapt the packages to new releases of the packages they use ¡  no ‘big bang’ integration but small increments l  To avoid the ‘morning-after syndrome’ the dependency tree must not have any cycles
  121. 121. Package Structure as a Directed Acyclic Graph MyApplication Message Window Task Window MyTasks Database Tasks Windows MyDialogs
  122. 122. Breaking the Cycle with DIP MyDialogs X MyDialogs X «interface» X Server MyApplication Y MyApplication Y
  123. 123. Breaking the Cycle with a New Package MyApplication Message Window Task Window MyTasks Database Tasks Windows MyDialogs NewPackage
  124. 124. Breaking the Cycle – a Corollary l The package structure cannot be designed top–down but it evolves as the system grows and changes l Package depency diagrams are not about the function of the application but they are a map to the buildability of the application
  125. 125. SDP: The Stable-Dependencies Principle Depend in the direction of stability. l  Designs cannot be completely static ¡  some volatility is required so that the design can be maintained ¡  CCP: some packages are sensitive to certain types of changes l  A volatile package should not be depended on by a package that is difficult to change ¡  a package designed to be easy to change can (accidentally) become hard to change by someone else hanging a dependency on it!
  126. 126. Stable and Instable Packages Y X l  ‘Stable’ = not easy to change ¡ how much effort is needed to change a package: size, complexity, clarity, incoming dependencies l  If other packages depend on a package, it is hard to change (i.e. stable)
  127. 127. Stability Metrics l  Affarent couplings Ca ¡ the number of classes outside this package that depend on classes within this package l  Efferent couplings Ce ¡ the number of classes inside this package that depend on classes outside this package l  Instability I ¡ I = Ce / (Ca + Ce) ¡ I = 0: maximally stable package ¡ I = 1: maximally instable package l  Dependencies ¡ C++: #include ¡ Java: import, qualified names
  128. 128. SDP l The I metric of a package should be larger than the I metrics of the packages that depends on Instable Instable I=1 I=1 Instable I=1 Stable I=0 Flexible I>0
  129. 129. Fixing the Stability Violation Using DIP Stable Flexible U Stable C UInterface U «interface» IU Flexible C
  130. 130. SAP: The Stable-Abstractions Principle A package should be as abstract as it is stable. l  A stable package should be abstract so that stability does not prevent it from being extended l  An instable package should be concrete since the instability allows the concrete code to be changed easily l  SDP + SAP = DIP for packages ¡  dependencies run in the direction of abstractions l  Since packages have varying degrees of abstractness, we need a metric to measure the abstractness of a package
  131. 131. Measuring Abstractness l The number of classes in the package Nc l The number of abstract classes in the package Na ¡ abstract class = at least one pure interface and cannot be instantiated l Abstractness A ¡ A = Na / Nc ¡ A = 0: no abstract classes ¡ A = 1: only abstract classes
  132. 132. The Abstractness–Instability Graph (0,1) (1,1) A (0,0) I (1,0)
  133. 133. Recap: Package Cohesion and Coupling l  REP, CRP, and CCP: cohesion within a package ¡ ‘bottom–up’ view of partitioning ¡ classes in a packages must have a good reason to be there ¡ classes belong together according to some criteria l political factors l dependencies between the packages l package responsibilities l  ADP, SDP, and SAP: coupling between packages ¡ dependencies accross package boundaries ¡ relationships between packages l technical l political l volatile
  134. 134. FACTORY l DIP: prefer dependencies on abstract classes ¡ avoid dependencies on concrete (and volatile!) classes ¡ any line of code that uses the new keyword violates DIP: Circle c = new Circle(origin, 1); ¡ the more likely a concrete class is to change, the more likely depending on it will lead to trouble l How to create instances of concrete objects while depending only on abstract interfaces → FACTORY
  135. 135. Example: Creating Shapes Violates DIP «creates» Application «interface» Shape Square Circle
  136. 136. Example: Shapes Using FACTORY Application «interface» ShapeFactory «interface» Shape +makeSquare() +makeCircle() ShapeFactory Implementation «creates» Square Circle
  137. 137. Example: Removing the Dependency Cycle public interface ShapeFactory { public Shape make(Class<? extends Shape> t); } public class ShapeFactoryImplementation implements ShapeFactory { public Shape make(Class<? extends Shape> t) { if (t == Circle.class) return new Circle(); else if (t == Square.class) return new Square(); throw new Error(); } } ShapeFactory sf = new ShapeFactoryImplementation(); Shape s1 = sf.make(Circle.class); Shape s2 = sf.make(Square.class);
  138. 138. Benefits of FACTORY l Implementations can be substituted easily l Allows testing by spoofing the actual implementation Application ShapeFactory Implementation 1 «interface» ShapeFactory «creates» ShapeFactory Implementation 2 «creates» «interface» Shape Square ShapeFactory Implementation 3 Circle «creates»
  139. 139. FACTORY – the Flip Side l Factory is a powerful abstraction ¡ strictly thinking DIP entails that you should use factories for every volatile class l Do not start out using factories ¡ can cause unnecessary complexity ¡ add them when the need becomes great enough
  140. 140. Design Patterns: Set 2 l COMPOSITE l OBSERVER l ABSTRACT SERVER l ADAPTER l BRIDGE l PROXY l STAIRWAY TO HEAVEN
  141. 141. COMPOSITE «interface» Shape 0..* +draw() Circle Square Composite Shape +add(Shape) +draw() «delegates»
  142. 142. COMPOSITE and COMMAND Sensor Command 0..* Composite Command l  Sensor and Command: one-to-one association l  COMPOSITE provides a way to have one-to-many behaviour without one-to-many association ¡ list management and iteration appears only once in the composite class l  Cf. java.awt.geom.GeneralPath
  143. 143. OBSERVER l  Service call can be seen as a global event to which the related modules can react ¡ creator and handler(s) of the event do not have to know one another → no direct dependency l  Define an object keeps the data model (Subject) l  Delegate all ‘view’ functionality to decoupled and distinct Observer objects ¡ register to Subject at creation l  When Subject changes, it notifies all registered Observers ¡ Observer can query Subject for the data that it is responsible for monitoring l  The number and type of Observers can be configured dynamically at run time
  144. 144. Synchronous Event-Handling Observers a b c x 60 30 10 y 50 30 20 z 80 10 10 a b c change notifications requests, modifications a = 50% b = 30% c = 20% Subject
  145. 145. OBSERVER: Pull Model Subject 0..* «observes» +register(Observer) +unregister(Observer) #notify() Concrete Subject +getState() +setState() «interface» Observer +update() «registers» Concrete Observer +update()
  146. 146. OBSERVER: Push Model Subject +register(Observer) +unregister(Observer) +notify(Message) Concrete Subject +getState() +setState() 0..* «observes» Observer +update(Message) Concrete «registers» Observer
  147. 147. Features l  Use Observer when ¡ an abstraction has two aspects, one dependent on the other ¡ a change to one object requires changing others, and you do not know how many objects need to be changed ¡ an object should be able to notify other objects without assumptions about these objects l  Observer is a widely used pattern: once you understand it, you see uses for it everywhere ¡ you can register observers with all kinds of objects rather than writing those objects to explicitly call you l  Cf. ¡ java.awt.event.ActionListener ¡ java.util.Observer and java.util.Observable
  148. 148. ABSTRACT SERVER – A Motivating Example l Design software for a simple table lamp ¡ switch: on/off ¡ light: on/off l The simple design violates ¡ DIP ¡ OCP Switch Light +turnOn() +turnOff()
  149. 149. Example: A Bad Way to Extend Switch Switch Light +turnOn() +turnOff() FanSwitch Fan +turnOn() +turnOff()
  150. 150. Example: Extending Switch with ABSTRACT SERVER Switch «interface» Switchable +turnOn() +turnOff() Light Fan +turnOn() +turnOff() +turnOn() +turnOff()
  151. 151. Who Owns the Interface? l Interfaces belong to the client, not to the derivative ¡ Switch cannot be deployed without Switchable ¡ Switchable can deployed without Light l Inheritance hierarchies usually should not be packaged together ¡ package clients with the interfaces they control l Cf. ¡ java.io.Closeable, java.io.Flushable ¡ javax.swing.table.TableModel
  152. 152. ADAPTER l Potential SRP violation in ABSTRACT SERVER: ¡ Light and Switchable may not change for the same reasons ¡ what if Light cannot be inherited? l Solution: add a class that can be adapted to the interface ¡ drawback: extra classes, instantations
  153. 153. Example: Object-Form Adapter Switch «interface» Switchable +turnOn() +turnOff() Light Adapter +turnOn() +turnOff() «delegates» Light +turnOn() +turnOff()
  154. 154. Example: Class-Form Adapter Switch «interface» Switchable +turnOn() +turnOff() Light Adapter Light +turnOn() +turnOff() +turnOn() +turnOff()
  155. 155. BRIDGE – A Motivating Example l  Modelling animal characteristics ¡  each type of animal can have different number of legs (integer) ¡  each type of animal can have different type of movement: fly, walk or crawl ¡  an animal must be able to return the number of legs when asked ¡  an animal must be able to calculate how long it would take to move a distance given the type of terrain l  Variation in number of legs: a member variable with get/set methods l  Variation in movement type: ¡  a member variable to indicate the type and to select different code for movement l  tight coupling, messy code ¡  animal types are derived from a base class l  need to manage subtypes of animals l  no animals with more than one type of movement l  subtyping based on one property; what about classifying them as mammals, reptiles and birds?
  156. 156. Example: Bridging Two Hierarchies Animal «delegates» Movement +move() Bird Reptile Mammal Fly Walk Crawl l Encapsulate the behaviour (i.e. movement) into a class l The animal class contains an object that has the appropriate behaviour
  157. 157. Commonality and Variability l  Commonality analysis ¡ what are the common elements among the elements ¡ define a family to which the elements belong and a context where things vary ¡ find the structure that is unlikely to change over time l  Variability analysis ¡ how things vary within the context of commonality (variability only makes sense within a given commonality) ¡ find the structure that is likely to change l  Shortly: When the type hierarchy has more than one degree of freedom ¡ separate the hierarchies ¡ tie them together with a bridge
  158. 158. PROXY l Allows to cross a barrier without either of the participants knowing about it ¡ database ¡ network l Theory: PROXY can be inserted in between two collaborating objects without them knowing about it l Reality: not so trivial…
  159. 159. Example: Web Shopping Cart Customer -name -address -billingInfo 0..* Order -date -status 0..* Item Product -quantity -name -price -sku
  160. 160. Example: Order Proxy «interface» Order DB Order DB Proxy «delegates» Order Implementation l Interface that declares all the methods that clients need to invoke l Class that implements those methods without knowledge of the database l Proxy that knows about the database
  161. 161. Example: Order Proxy (cont’d) public interface Order { public String getCustomerId(); public void addItem(Product p, int quantity); public int total(); } public class OrderImp implements Order { private List<Item> itsItems; public int total() { int total = 0; for (Item item : itsItems) total += item.getProduct().getPrice() * item.getQuantity(); return total; } /* rest of the implementation omitted */ }
  162. 162. Example: Order Proxy (cont’d) public class OrderProxy implements Order { public int total() { OrderImp imp = new OrderImp(getCustomerId()); ItemData[] itemDataArray = DB.getItemsForOrder(orderId); for (ItemData item : itemDataArray) imp.addItem(new ProductProxy(item.sku), item.qty); return imp.total(); } /* rest of the implementation omitted */ }
  163. 163. STAIRWAY TO HEAVEN l Achieves dependency inversion (like PROXY) l Employs a variation on the class form of ADAPTER l Only useful in languages supporting multiple inheritence l Completely seperates knowledge of the database away from the business rules of the application
  164. 164. STAIRWAY TO HEAVEN (cont’d) Persistent Object +write() +read() Product Persistent Product Assembly Persistent Assembly
  165. 165. Design Patterns: Set 3 l The VISITOR family ¡ VISITOR ¡ ACYCLIC VISITOR ¡ DECORATOR ¡ EXTENSION OBJECT l STATE
  166. 166. VISITOR l The VISITOR family allows new methods to be added to existing hierarchies without modifying the hierarchies l Every derivative of the visited hierarchy has a method in VISITOR l Dual dispatch: two polymorphic dispatches
  167. 167. Example: Modem Hierarchy «interface» Modem +dial() +send() +hangup() +receive() Hayes Zoom Ernie
  168. 168. Example: Modem Hierarchy (cont’d) «interface» Modem «interface» ModemVisitor +dial() +send() +hangup() +receive() +accept(ModemVisitor) +visit(Hayes) +visit(Zoom) +visit(Ernie) UnixModem Configurator Hayes Zoom Ernie WindowsModem Configurator
  169. 169. Example: Modem Hierarchy (cont’d) public interface Modem { public void dial(String pno); public void hangup(); public void send(char c); public char receive(); public void accept(ModemVisitor v); } public interface ModemVisitor { public void visit(HayesModem modem); public void visit(ZoomModem modem); public void visit(ErnieModem modem); }
  170. 170. Example: Modem Hierarchy (cont’d) public class HayesModem implements Modem { public void accept(ModemVisitor v) { v.visit(this); } /* rest of the implementation omitted */ } public class UnixModemConfigurator implements ModemVisitor { public void visit(HayesModem m) { m.setConfigurationString("&s1=4&D=3"); } public void visit(ZoomModem m) { m.setConfigurationValue(42); } public void visit(ErnieModem m) { m.setInternalPattern("C is too slow"); } }
  171. 171. Example: Modem Hierarchy (cont’d) l To configure a modem for Unix, create an instance of the visitor and pass it to accept l The appropriate derivative calls visit(this) l New OS configuration can be added by adding a new derivative of the visitor
  172. 172. VISITOR as a Matrix Unix Windows Hayes Initialization of Hayes in Unix Initialization of Hayes in Windows Zoom Initialization of Zoom in Unix Initialization of Zoom in Windows Ernie Initialization of Ernie in Unix Initialization of Ernie in Windows
  173. 173. Observations l  In VISITOR ¡ the visited hierarchy depends on the base class of the visitor hierarchy ¡ the base class of the visitor hierarchy has a function for each derivative of the visited hierarchy l  A cycle of dependencies ties all the visited derivatives together ¡ difficult to compile incrementally ¡ difficult to add new derivatives of visited hierarchy l  Visitor work well if the hierarchy is not modified often
  174. 174. ACYCLIC VISITOR l For a volatile hierarchy ¡ new derivatives are created ¡ quick compilation time is needed l ACYCLIC VISITOR breaks the dependency cycle by making the visitor base class degenerate (i.e. it has no methods)
  175. 175. Example: Modem Hierarchy «interface» Modem «degenerate» ModemVisitor +dial() +send() +hangup() +receive() +accept(ModemVisitor) Hayes Zoom Ernie «interface» HayesVisitor «interface» ZoomVisitor «interface» ErnieVisitor +visit(Hayes) +visit(Zoom) +visit(Ernie) UnixModem Configurator
  176. 176. Example: Modem Hierarcy (cont’d) public interface Modem { public void dial(String pno); public void hangup(); public void send(char c); public char receive(); public void accept(ModemVisitor v); } public interface ModemVisitor { }
  177. 177. Example: Modem Hierarchy (cont’d) public interface ErnieModemVisitor { public void visit(ErnieModem m); } public class ErnieModem implements Modem { public void accept(ModemVisitor v) { try { ErnieModemVisitor ev = (ErnieModemVisitor)v; ev.visit(this); } catch (ClassCastException e) { } } /* rest of the implementation omitted */ }
  178. 178. Example: Modem Hierarchy (cont’d) public class UnixModemConfigurator implements ModemVisitor, HayesVisitor, ZoomVisitor, ErnieVisitor { public void visit(HayesModem m) { m.setConfigurationString("&s1=4&D=3"); } public void visit(ZoomModem m) { m.setConfigurationValue(42); } public void visit(ErnieModem m) { m.setInternalPattern("C is too slow"); } }
  179. 179. Observations l Breaking the dependency cycle ⇒ ¡ easier to add visited derivatives ¡ solution is much more complex ¡ timing of the type casting is hard to characterize l ACYCLIC VISITOR is like a sparse matrix ¡ visitor classes do no have to implement visit functions for all visited derivatives
  180. 180. DECORATOR l Allows attaching additional responsibilities to an object dynamically (i.e. at runtime) l Provides a flexible alternative to subclassing for extending functionality l Allows adding responsibilities to an object without adding methods to its interface
  181. 181. Example: Loud Dial Modem «interface» Modem itsModem +dial(…) +setVolume(int) HayesModem ZoomModem ErnieModem LoudDial Modem «delegates» public void dial(…) { itsModem.setVolume(11); itsModem.dial(…); }
  182. 182. Example: Loud Dial Modem (cont’d) public interface Modem { public void dial String(pno); public void setSpeakerVolume(int volume); } public class HayesModem implements Modem { private String itsPhoneNumber; private int itsSpeakerVolume; public void dial(String pno) { itsPhoneNumber = pno; } } public void setSpeakerVolume(int volume) { itsSpeakerVolume = volume; }
  183. 183. Example: Loud Dial Modem (cont’d) public class LoudDialModem implements Modem { private Modem itsModem; public LoudDialModem(Modem m) { itsModem = m; } public void dial(String pno) { itsModem.setSpeakerVolume(11); itsModem.dial(pno); } } public void setSpeakerVolume(int volume) { itsModem.setSpeakerVolume(volume); }
  184. 184. Observations l Multiple decorators: base class decorator ¡ supplies the delegation code ¡ actual decorators derive from the base class and override only those methods they need l Cf. ¡ Java I/O streams: BufferedReader keyboard = new BufferedReader( new InputStreamReader(System.in)); ¡ javax.swing.JScrollPane
  185. 185. EXTENSION OBJECT l More complex than VISITOR but more powerful l Each object in the hierarchy ¡ maintains a list of special extension objects ¡ provides a method that allows the extension object to be looked up by name l Extension object provides methods that manipulate the original hierarchy object
  186. 186. Example: Bill-of-Materials Part +getExtension(String) +addExtension(String, PartExtension) 0..* «marker» PartExtension «marker» BadPartExtension Assembly PiecePart «interface» CSVPartExtension +getXMLElement() 0..* «interface» XMLPartExtension +getCSV() XMLAssembly Extension XMLPiecePart Extension CSVAssembly Extension CSVPiecePart Extension
  187. 187. STATE l Allows an object to alter its behaviour when its internal state changes ¡ the object will appear to change its class l Typically used to change the behaviour according to a state transition diagram l Other implementations for an FSM ¡ nested switch/case statement ¡ transition table
  188. 188. Example: Turnstile FSM pass/alarm Locked pass/lock coin/unlock Unlocked coin/thankyou
  189. 189. Example: Turnstile Turnstile +coin() +pass() #lock() #unlock() #thankyou() #alarm() «interface» TurnstileState +coin(Turnstile) +pass(Turnstile) Turnstile LockedState Turnstile UnlockedState
  190. 190. Example: Turnstile (cont’d) public interface TurnstileState { public void coin(Turnstile t); public void pass(Turnstile t); } public class LockedTurnstileState implements TurnstileState { public void coin(Turnstile t) { t.setUnlocked(); t.unlock(); } public void pass(Turnstile t) { t.alarm(); } } public class UnlockedTurnstileState implements TurnstileState { public void coin(Turnstile t) { t.thankyou(); } } public void pass(Turnstile t) { t.setLocked(); t.lock(); }
  191. 191. Example: Turnstile (cont’d) public class Turnstile { private static TurnstileState lockedState = new LockedTurnstileState(); private static TurnstileState unlockedState = new UnlockedTurnstileState(); private TurnstileController turnstileController; private TurnstileState state = lockedState; public Turnstile(TurnstileController action) { turnstileController = action; } public void coin() public void pass() public void setLocked() public void setUnLocked() public boolean isLocked() public boolean isUnlocked() protected void thankyou() protected void alarm() protected void lock() protected void unlock() } { { { { { { { { { { state.coin(this); } state.pass(this); } state = lockedState; } state = unlockedState; } return state == lockedState; } return state == unlockedState; } turnstileController.thankyou(); } turnstileController.alarm(); } turnstileController.lock(); } turnstileController.unlock(); }
  192. 192. STATE vs. STRATEGY l Common ¡ context class ¡ delegation to a polymorphic base class that has several derivatives l Difference ¡ STATE: derivatives hold a reference back to the context class ¡ STRATEGY: no such constraint or intent l All instances of STATE are also instances of STRATEGY
  193. 193. Observations l  Very strong separation between actions and the logic of state machine ¡ action in the context class ¡ logic distributed through the derivatives of the state class l  Simple to change one without affecting the other ¡ reuse the context class with different state logic ¡ create subclasses of context class that modify the action without affecting the logic l  Costs ¡ writing state derivatives is tedious ¡ the logic is distributed, no single place to see it all
  194. 194. RECAPITULATION AND CONCLUSIONS
  195. 195. Design Patterns (revisited) Abstract Server Memento Builder Proxy Stairway to Heaven Adapter Iterator Bridge Extension Object Command Composite Decorator Active Object Visitor Flyweight Interpreter Strategy Acyclic Visitor Chain of Responsibility Mediator State Observer Template Method Prototype Factory Method Factory Monostate Facade Singleton Null Object
  196. 196. Design Principles (revisited) 1.  2.  3.  4.  5.  Single-Responsibility Principle Open–Closed Principle Liskov Substitution Principle Depency-Inversion Principle Interface-Segregation Principle
  197. 197. Principles, Patterns, and Practices Context research, experience needs Practice System concretization Theory Abstraction of practices Forces know-how motivation, synthesis Principles Patterns
  198. 198. Examinations l Electronic examination ¡ opens May 6, 2013 ¡ closes September 30, 2013 l You can take the examination at most three (3) times l For instructions and examination time reservations, see https://tenttis.utu.fi/
  199. 199. Assessment l Examination: 18 points l Voluntary exercise work: 2 bonus points l Grading (based on 18 points): ¡ points: ¡ points: ¡ points: ¡ points: ¡ points: [9, 10] ⇒ grade: 1 (10, 12] ⇒ grade: 2 (12, 14] ⇒ grade: 3 (14, 16] ⇒ grade: 4 (16, 20] ⇒ grade: 5
  200. 200. Fin.

×