1 / 322

Chapter 2

Chapter 2. Design Principles and Design Patterns. Object-Oriented Design Principles. OO Design vs. OO Programming. Object-Oriented Design a method for decomposing software architectures based on the objects every system or subsystem manipulates

barth
Download Presentation

Chapter 2

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 2 Design Principles and Design Patterns

  2. Object-Oriented Design Principles

  3. OO Design vs. OO Programming • Object-Oriented Design • a method for decomposing software architectures • based on the objects every systemor subsystem manipulates • relatively independent of the programming language used • Object-Oriented Programming • construction of software systems as • Structured collection of Abstract Data Types (ADT) • Inheritance • Polymorphism • concerned with programming languages and implementation issues

  4. Polymorphism • Behavior promised in the public interface of superclass objects • implemented by subclass objects • in the specific way required for the subclass • Why Is this Important? • Allow subclasses to be treated like instances of their superclasses • Flexible architectures and designs • high-level logic defined in terms of abstract interfaces • relying on the specific implementation provided by subclasses • subclasses can be added without changing high-level logic

  5. Signs of Rotting Design • Rigidity (僵硬性) • code difficult to change • management reluctance(拒絶) to change anything becomes policy • Fragility (易碎性) • even small changes can cause cascading effects • code breaks in unexpected places • Immobility(固定性) • code is so tangled(糾結) that it's impossible to reuse anything • Viscosity(黏滯性) • much easier to hack(亂砍) than to preserve original design

  6. Causes of Rotting Design • Changing Requirements • is inevitable • "All systems change during their life-cycles. This must be borne in mind when developing systems expected to last longer than the first version". (I. Jacobson, OOSE, 1992) • Dependency Management • the issue of couplingand cohesion • It can be controlled! • create dependency firewalls • see DIP example

  7. Principle #1 The Open-Closed Principle:

  8. Open-Closed Principle (OCP) • "Software Systems change during their life time" • both better designs and poor designs have to face the changes; • good designs are stable Software entities should be open for extension, but closed for modification B. Meyer, 1988 / quoted by R. Martin, 1996 • Be open for extension • module's behavior can be extended • Be closed for modification • source code for the module must not be changes • Modules should bewritten so they can be extended withoutrequiring them to be modified

  9. The Open-Closed Principle • OCP attacks software rigidity and fragility! • When one change causes a cascade of changes • The Open-Closed Principle (OCP) states: • we should attempt to design modules that never need to be changed. • extend the behavior of the system by adding new code. We do not modify old code • Modules that conform to OCP meet two criteria: • Open for Extension - the behavior can be extended to meet new requirements • Closed for Modification - the source code of the module is not allowed to change

  10. Abstraction is the Key! • Abstraction • “Denotes the essential characteristics of an object that distinguish it from all other kinds of objects and thus provides crisply defined conceptual boundaries relative to the perspective of the viewer” -- Grady Booch • Fundamental technique of dealing with complexity • Focuses on the outside view of an object and separates object’s behavior from its implementation

  11. Encapsulation • Encapsulation • “Mechanism used to hide the data, internal structure, and implementation details of an object. All interaction with the object is through a public interface of operations” -- Craig Larman • Classes should be opaque(不透明) • Classes should not expose their internal implementation details

  12. Information Hiding in Java • Use private members and appropriate accessors and mutators when possible • Example: • Replace • public float accuracy; • With private float accuracy; public float getAccuracy ( ) { return (accuracy); } public void setAccuracy (float acc) { accuracy = acc; }

  13. Example: “Closed Client” • Client and Server are concrete classes • Client class uses Server class • If Client object wants to switch to a different Server object, what would need to happen? Client Server Client code needs to be modified to name the new Server class

  14. Example : “Open Client” Client AbstractServer • How is this “open” ? Server Since the Client depends on the AbstractServer, we can simply switch the Client to using a different Server, by providing a new Server implementation. Client code is unaffected!

  15. Open the door ... • How to make the Car run efficiently with a TurboEngine? • Only by changing the Car! • ...in the given design

  16. ... But Keep It Closed! • A class must not depend on a concrete class! • It must depend on an abstract class ... • ...using polymorphic dependencies (calls)

  17. Strategic Closure "No significant program can be 100% closed " R.Martin, “The Open-Closed Principle,” 1996 • Closure not complete but strategic • Use abstraction to gain explicit closure • provide class methods which can be dynamically invoked • to determine general policy decisions • design using abstract ancestor classes • Use "Data-Driven" approach to achieve closure • place volatile policy decisions in a separate location • e.g. a file or a separate object • minimizes future change locations

  18. OCP Heuristics Make all object-data private No Global Variables! • Changes to public data are always at risk to “open” the module • They may have a rippling effect requiring changes at many unexpected locations; • Errors can be difficult to completely find and fix. Fixes may cause errors elsewhere.

  19. OCP Heuristics (2) • RTTI is ugly and dangerous • If a module tries to dynamically cast a base class pointerto several derived classes, any time you extend theinheritance hierarchy, you need to change the module • recognize them by type switch-es or if-else-if structures • Not all these situations violate OCP all the time • when used only as a "filter" RTTI is Ugly and Dangerous!

  20. Another OCP Example • Consider the following method: • The job of the above method is to total the price of all parts in the specified array of parts. • Does this conform to OCP? • YES! If Part is a base class or an interface and polymorphism is being used, then this class can easily accommodate new types of parts without having to be modified!

  21. OCP Example (contd.) • But what if the Accounting Department now decreed that motherboard parts and memory parts have a premium applied when figuring the total price? • Would the following be a suitable modification? Does it conform to OCP?

  22. OCP Example - OCP Conformance • No! Every time the Accounting Department comes out with a new pricing policy, we have to modify totalPrice ( ) method. This is not“Closed for modification” • These policy changes have to be implemented some place, so what is a solution? • Version 1 - Could incorporate the pricing policy in getPrice ( ) method of Part.

  23. OCP Example (contd.) • Here are example Part and Concrete Part classes: Add method Code in concrete classes • Does this work? Is it “closed for modification”? • No. We must now modify each subclass of Part whenever the pricing policy changes!

  24. How to make it “Closed for Modification” • Better idea - have a PricePolicy class which can be used to provide different pricing policies:

  25. OCP Example (contd.)

  26. OCP Example (contd.) • With this solution we can dynamically set pricing policies at run time by changing the PricePolicy object that an existing Part object refers to. • Any other solution? Both price of a Part and its associated PricePolicy could be stored in a database.

  27. Single Choice Principle Corollary to OCP The Single Choice Principle: Whenever a software system must support a set of alternatives, ideally only one class in the system knows the entire set of alternatives!

  28. The Open-Closed PrincipleThings to Remember • OCP is the heart of OO design • Well designed code can be extended without modification • Primary mechanisms: abstraction and polymorphism (and inheritance hierarchies) • Conformance to this principle yields the greatest level of reusability and maintainability • It is not possible to have all modules of a software system satisfy the OCP, but we need to attempt to minimize the number of modules that do not satisfy it.

  29. Principle #2 The Liskov Substitution Principle:

  30. The Liskov Substitution Principle • The key of OCP: Abstraction andPolymorphism • Implemented by inheritance • How do we measure the quality of inheritance? • Inheritance should ensure that any property proved about supertype objects also holds for subtype objects • B. Liskov, 1987 • Functions that use pointers or references to base classes • must be able to use objects of derived classes • without knowing it. • R. Martin, 1996

  31. The Liskov Substitution Principle • The Liskov Substitution Principle (LSP) seems obvious given polymorphism • For example: public void drawShape (Shape s) { // code here } • The drawShape method should work with any subclass of the Shape superclass (or, if Shape is a Java interface, it should work with any class that implements the Shape interface) • So what is the big deal with LSP?

  32. The Liskov Substitution Principle • If a function does not satisfy the LSP, then it probably makes explicit reference to some or all of the subclasses of its superclass. Such a function also violates the Open-Closed Principle, since it may have to be modified whenever a new subclass is created.

  33. Inheritance Appears Simple class Bird {// has beak, wings,... public void fly() {…};// Bird can fly }; class Parrot extends Bird { // Parrot is a bird public void mimic() {…}; // Can Repeatwords... }; // ... Parrot mypet; mypet.mimic(); // my pet being a parrot can Mimic() mypet.fly(); // my pet “is-a” bird, can fly

  34. Penguins Fail to Fly! class Penguin extends Bird { public void fly() { error (“Penguins don’t fly!”); } }; void PlayWithBird (Bird abird){ abird.fly(); // OK if Parrot. // if bird happens to be Penguin...OOOPS!! } • Does not model: “Penguins can’t fly” • It models “Penguins may fly, but if they try it is error” • Run-time error if attempt to fly  not desirable • Think about Substitutability - Fails LSP

  35. Design by Contract • Advertised Behavior of an object: • advertised Requirements (Preconditions) • advertised Promises (Postconditions) • When redefining a method in a derivate class, you may only replace its precondition by a weaker one, and • its postcondition by a stronger one • B. Meyer, 1988 • Derived class servicesshould require nomore and promise no less int Base::f(int x); // REQUIRE: x is odd // PROMISE: return even int int Derived::f(int x); // REQUIRE: x is int // PROMISE: return 8

  36. Square IS-A Rectangle? • Should I inherit Square from Rectangle? Square ?

  37. Another LSP Example • Consider the following Rectangle class: // A very nice Rectangle class public class Rectangle { private double width; private double height; public Rectangle (double w, double h) { width = w; height = h; } public double getWidth ( ) { return width;} public double getHeight ( ) { return height;} public void setWidth (double w) { width = w; } public void setHeight (double h) {height = h;} public double area ( ) { return (width * height);} }

  38. LSP Example (contd.) • Assume we need a Square class. Clearly a square is a rectangle, so the Square class should be derived from the Rectangle class. • Observations: • A square does not need both a width and a height as attributes, but it will inherit them from Rectangle anyway. So each Square object wastes a little memory -- but this is not a major concern. • The inherited setWidth ( ) and setHeight ( ) methods are not really appropriate for a Square, since the width and height of a square are identical. So we’ll need to override the methods setWidth ( ) and setHeight ( ).

  39. LSP Example (contd.) • Here’s the Square class: // A Square class public class Square extends Rectangle { public Square (double s) { super (s, s);} public void setWidth (double w) { super.setWidth (w); super.setHeight(w); } public void setHeight (double h) { super.setWidth (h); super.setHeight (h); } } setWidth ( ) and setHeight ( ) overridden to reflect Square semantics

  40. LSP Example (contd.) • Everything looks good. But consider this function! public class TestRectangle { // Define a method that takes a Rectangle reference. public static void testLSP (Rectangle r) { r.setWidth (4.0); r.setHeight (5.0); System.out.println (“Width is 4.0 and Height is 5.0” + “, Area” + r.area () ); if (r.area ( ) == 20.0 ){ System.out.println (“Looking good \n”); else System.out.println(“Huh?? What kind of rectangle is this?? \n”); }

  41. LSP Example (Contd.) public static void main (String args[] ) { // Create a Rectangle and a Square Rectangle r = new Rectangle (1.0, 1.0); Square s = new Square (1.0); // Now call the testLSP method. According to LSP it should work for either // Rectangles or Squares. Does it? testLSP ( r ); testLSP (s); } }

  42. LSP Example (contd.) • Test program output: Width is 4.0 and Height is 5.0, so Area os 20.0 Looking good! Width is 4.0 and Height is 5.0, so Area is 25.0 Huh?? What kind of rectangle is this?? • Looks like we violated LSP!

  43. The Problem? • The programmer of the testLSP ( ) method made the reasonable assumption that changing the width of a Rectangle leaves its height unchanged. • Passing a Square object to such a method results in problems, exposing a violation of LSP. • The Square and Rectangle classes look self consistent and valid. Yet a programmer, making reasonable assumptions about the base class, can write a method that causes the design model to break down. • Solutions cannot be viewed in isolation, they must also be viewed in terms of reasonable assumptions that might be made by the users of the design.

  44. The Problem (contd.) • A mathematical square might be a rectangle, but a Square object is a not a Rectangle object, because the behavior of a Square object is not consistent with the behavior of a Rectangle object! • Behaviorally, a Square is not a Rectangle! A Square object is hence not polymorphic with a Rectangle object. • Hint on LSP violation: when simple methods such as the setWidth and setHeight have to be overridden, inheritance needs to be re-examined!

  45. LSP is about Semantics and Replacement • The meaning and purpose of every method and class must be clearly documented • Lack of user understanding will induce de facto (事實的) violations of LSP • Replaceability is crucial • Whenever any class is referenced by any code in any system, any future or existing subclasses of that class must be 100% replaceable • Because, sooner or later, someone will substitute a subclass; • it’s almost inevitable.

  46. LSP and Replaceability • Any code which can legally call another class’s methods • must be able to substitute any subclass of that class without modification: Client Service Class Service Class Client Unexpected Subclass

  47. Alternative Solution: • Favor Composition over Inheritance

  48. Composition • Method of reuse in which new functionality is obtained by creating an object composed of other objects • The new functionality is obtained by delegating functionality to one of the objects being composed. • Sometimes also called Delegation, Aggregation or Containment (although some associate different meanings to these) • Aggregation - when one object owns or is responsible for another object and both objects have identical lifetimes (GoF) • Aggregation - when one object has a collection of objects that can exist on their own (UML) • Containment - a special kind of composition in which the contained object is hidden from other objects and access to the contained object is only via the container object (Coad) • Delegation - when one object delegates the execution of a behavior to another object (Bruegge)

  49. Composition • Composition can be • By reference • By value • C++ allows composition by value or by reference • Java allows only by reference

  50. Pros and Cons of Composition • Advantages • Contained objects are accessed by the containing class solely through their interfaces • “Black-box” reuse - internal details of contained objects are not visible • Good encapsulation • Fewer implementation dependencies • Each class is focused on just one task • Can be defined dynamically at run-time • Disadvantages • Resulting systems often tend to have more objects • Interfaces must be defined carefully in order to use many different objects as composition blocks

More Related