Presentation is loading. Please wait.

Presentation is loading. Please wait.

Lecture 16 Composition vs Inheritance: The Final Chapter.

Similar presentations


Presentation on theme: "Lecture 16 Composition vs Inheritance: The Final Chapter."— Presentation transcript:

1 Lecture 16 Composition vs Inheritance: The Final Chapter

2 Inheritance* Drawbacks Inheritance imposes a tight coupling between parent class and its subclasses. Inheritance imposes a tight coupling between parent class and its subclasses. The parent class / child class relationship is brittle. A change in the parent class could break its child classes even though there are no changes in the child classes. The parent class / child class relationship is brittle. A change in the parent class could break its child classes even though there are no changes in the child classes. Inheritance exposes implementation details thus violating encapsulation. Inheritance exposes implementation details thus violating encapsulation. * This presentation assumes implementation inheritance, not interface inheritance.

3 Inheritance Guidelines The decision to use inheritance should not be made lightly. The decision to use inheritance should be make on sound OO principles: The decision to use inheritance should not be made lightly. The decision to use inheritance should be make on sound OO principles:  “ IS A” – Is the subclass indeed a type of parent class?  In many cases “IS A” criteria isn’t good enough to make this determination.  Will the type hierarchy violate the Liskov Substitution Principle?  Per “Design by Contract”…  Are the preconditions of an overridden method the same or weaker than that of the parent type?  Are the postconditions the same or stronger?  Is the base type designed and documented for inheritance?  How volatile is the base type?

4 Liskov Substitution Principle If for each object o 1 of type S there is an object o 2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o 1 is substituted for o 2 then S is a subtype of T. If for each object o 1 of type S there is an object o 2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o 1 is substituted for o 2 then S is a subtype of T.  o 1 is an instance of a Subtype  o 2 is an instance of a Type  P is the Type that defines the behavior the object it realizes.  P should behave the same regardless of whether it realizes a Type ( o 2 ) or a Subtype ( o 1 ). Programmatically, a function or method using object of a base class should behave the same when it is made to use object of a class derived from the base class. Programmatically, a function or method using object of a base class should behave the same when it is made to use object of a class derived from the base class.  LSP is an OOD guideline stressing the importance of behavior over data.  Method overriding in derived classes is probably the biggest cause of LSP violations. Method overriding should be done with great impunity to avoid these violations.  Overriding an implemented method violates the “Dependency Inversion Principle” (depend on abstractions, not implementations).

5 Design By Contract To help with designing classes that conform to the Liskov Substitution Principle, Design by Contract (DbC) concepts can be employed to help facilitate proper class inheritance. To help with designing classes that conform to the Liskov Substitution Principle, Design by Contract (DbC) concepts can be employed to help facilitate proper class inheritance.  Preconditions define the minimum requirements that must be met before a method can execute.  Postconditions define what conditions the method is obligated to satisfy.  When applying Design By Contract to subclasses, DbC says… When redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one.

6 Design By Contract When using an object (derived or base) through its base class interface… When using an object (derived or base) through its base class interface…  The client must not require stronger preconditions on a method than the base class (i.e. there cannot be more preconditions than that required by the base class).  A method of a derived class must satisfy at least the same post conditions as the base class (i.e. the derived class cannot support less postconditions than the base).

7 Favor Composition Over Inheritance Composition is often the better choice for extending and adding functionality to a structure. Composition is often the better choice for extending and adding functionality to a structure. The “Open Closed Principle” can arguably be more effectively applied through composition than through inheritance. The “Open Closed Principle” can arguably be more effectively applied through composition than through inheritance.  “Open Closed Principle” - A class should be open for extension, but closed for modification.  Ideally, code should never have to be changed. New functionality can be added through…  Inheritance or in many cases…  Composition and Delegation!

8 Favor Composition over Inheritance Composition is the act of composing an object from other objects. Composition is the act of composing an object from other objects. Composition is expressed as a “has-a” or “knows-a” relationship. Composition is expressed as a “has-a” or “knows-a” relationship. Types of composition: Types of composition:  Association – One object uses another to perform some type of service (e.g. utility class).  Aggregation – Represents a whole/part relation. Aggregation implies that a complex object is composed of other objects (e.g. Account is composed of one or more policies). Notice that you could get composability by replacing inheritance with aggregation. Notice that you could get composability by replacing inheritance with aggregation.

9 Aggregation JavaUML Aggregation is a form of association representing a whole/part relationship between two classes. Aggregation implies that the whole is at a conceptually higher level than the part, whereas an association implies both classes are at the same conceptual level. An instance variable in the whole holds a reference to the part(s). The difference between association and aggregation is entirely conceptual and is focused strictly on semantics. In an aggregation relationship, the part class instance (tire) can outlive the whole class (car). The relationship is represented with a hollow diamond attached at the whole and an arrow pointing to the part.

10 Composition JavaUML Composition is a special form of aggregation, which implies the whole is responsible for the lifecycle of the part. Composition is also non-shared. So while the part doesn't necessarily need to be destroyed when the whole is destroyed, the whole is responsible for either keeping alive or destroying the part. The part cannot be shared with other wholes. The whole, however, can transfer ownership to another object, which then assumes lifetime responsibility. The above trivial example shows that water is composed of hydrogen and oxygen. The composition relationship is represented with a solid diamond attached at the whole and an arrow pointing to the part.

11 Composition over Inheritance: The Decorator Pattern Starbutts Coffee, a startup business, decides to offer some standard blends according to the following scheme: Starbutts Coffee, a startup business, decides to offer some standard blends according to the following scheme: Beverage description cost() getDescr() HouseblendDarkRoastDecafEspresso cost()

12 The Price of Success

13 Managing Complexity What happens when the price of milk goes up? How to update cost-calculation What happens when the price of milk goes up? How to update cost-calculation Try this Try this  Use a Beverage base class and add instance vaiables to represent the milk contribution  How does this stand up to change??

14 We Get This description milk soy mocha whip Beverage getDescription() cost() hasMilk() setMilk() hasSoy()... HouseblendDarkRoastDecafEspresso cost()

15 Meet the Decorator Pattern The preceding is an open-closed nightmare The preceding is an open-closed nightmare Combine the power of inheritance with extending the object’s behavior at runtime Combine the power of inheritance with extending the object’s behavior at runtime Start with a Beverage and extend it at run-time Start with a Beverage and extend it at run-time  Take a DarkRoast object  Decorate it with a Mocha object  Decorate that with a Whip object  Call cost() and use delegation to sum up the milk cost

16 We Obtain DarkRoast Mocha Whip cost()

17 Remarks Inheritance: Mocha is_a Beverage, etc. Inheritance: Mocha is_a Beverage, etc. To calculate cost start with the cost on Whip, delegate to Mocha and then delegate to DarkRoast. Which returns its cost to Mocha, which add this to its cost and returns that to Whip, which takes that and calculates the entire cost To calculate cost start with the cost on Whip, delegate to Mocha and then delegate to DarkRoast. Which returns its cost to Mocha, which add this to its cost and returns that to Whip, which takes that and calculates the entire cost The Decorator adds its own behavior either before or after delegating to the object it decorates to finish up the work. The Decorator adds its own behavior either before or after delegating to the object it decorates to finish up the work.

18 The Decorator Pattern Component ConcreteComponentDecorator Concrete Decorator A Concrete Decorator B methodA() methodB() methodA() methodB() methodA() methodB() methodA() methodB() methodA() methodB() Concrete WrappedObject Concrete WrappedObject

19 Explanation Components can be used on their own or decorated Components can be used on their own or decorated Each decorator has_a Component Each decorator has_a Component Decorators implement the same interface as the component they decorate Decorators implement the same interface as the component they decorate Concrete Decorator has an instance variable for the Component it wraps Concrete Decorator has an instance variable for the Component it wraps

20 Back to Starbutts Beverage Condiment Decorator MilkMochaWhip HouseBlendDarkRoast DecafEspresso cost() getDescr() component

21 Write the Code: Component public abstract class Beverage{ String description = “unknown beverage”; public String getDescription(){ return description;} public abstract double cost(); }

22 Write the Code: CondimentDecorator public abstract class CondimentDecorator extends Beverage{ public abstract double cost(); //force implementation }

23 Write the Code: ConcreteComponent public class Espresso extends Beverage{ public Espresso(){ description = “Espresso”;} public double cost(){ return 1.99;} } public class DarkRoast{... //etc }

24 Write the Code: ConcreteDecorator public class Mocha extends CondimentDecorator { Beverage beverage; public Mocha(Beverage beverage){ this.beverage = beverage;} public String getDescription(){ return beverage.getDescription() + “, Mocha”;} public double cost(){ return.20 + beverage.cost();} } etc

25 Build and Test public class Starbutts{ public static void main(String args[]){ Beverage beverage1 = new Espresso(); System.out.println(beverage1.getDescription() + “$” + beverage.cost()); Beverage beverage2 = new DarkRoast(); beverage2 = new Mocha(beverage2); beverage2 = new Whip(beverage2); System.out.println(beverage2.getDescription() + “$” + beverage2.cost());

26 Build and Test (Ctd) Beverage beverage3 = new HouseBlend(); beverage3 = new Soy(beverage3); beverage3 = new Mocha(beverage3); beverage3 = new Whip(beverage3); System.out.println(beverage3.getDescription () + “$” + beverage3.cost()); }

27 Now Use This The Decorator Pattern Combines Composition with Inheritance

28 Favor Composition over Inheritance – Decorator Pattern The Decorator pattern provides a common alternative to inheritance. Wrapper classes use the Decorator pattern. The Decorator pattern provides a common alternative to inheritance. Wrapper classes use the Decorator pattern. Decorator classes mirror the type of components they decorate. Decorator classes mirror the type of components they decorate.  They are the same type as the components they decorate either through inheritance or implementation. The decorator holds an instance of the component it decorates. In other words, the decorator is composed of the object it decorates. The decorator holds an instance of the component it decorates. In other words, the decorator is composed of the object it decorates.  Decorators are prevalent in many core Java packages e.g.  Java.io.FilterInputStream (wraps InputStream)  HttpServletResponseWrapper (wraps ServletResponse)

29 Favor Composition over Inheritance – Decorator Pattern Decorator classes mirror the type of components they decorate. Decorator classes mirror the type of components they decorate.  They are the same type as the components they decorate either through inheritance or implementation. Decorators are transparent to the client Decorators are transparent to the client The decorator holds an instance of the component it decorates. In other words, the decorator is composed of the object it decorates. The decorator holds an instance of the component it decorates. In other words, the decorator is composed of the object it decorates.

30 Favor Composition over Inheritance – Decorator Pattern Decorator Class Diagram

31 Favor Composition over Inheritance Inheritance Inheritance  Pros  Code sharing  Cons  Brittle  Tight coupling between parent/child classes Composition  Pros  Evaluated at runtime (dynamic binding)  Lightweight  Flexible  Cons  Increased system complexity Composition increases system flexibility. If we use composition, we can extend an object’s behavior dynamically, at runtime, adding new responsibilities to objects that we may not have thought about during design time. Another benefit of this technique is that we do not need to change existing code, and so the chances of introducing new bugs or unwanted effects are reduced.

32 Questions?

33 Object Oriented Design Principles Encapsulate what varies Encapsulate what varies Favor composition over inheritance Favor composition over inheritance Program to interfaces, not implementations Program to interfaces, not implementations Strive for loosely coupled designs between objects that interact Strive for loosely coupled designs between objects that interact Classes should be open for extension but closed for modification Classes should be open for extension but closed for modification  The open/closed principle is the single most important guide for an object oriented designer. Designing modules whose behavior can be modified without making source code modifications to that module is what yields the benefits of OOD. Abstractions should not depend on details. Details should depend on abstractions (Dependency Inversion Principle) Abstractions should not depend on details. Details should depend on abstractions (Dependency Inversion Principle)

34 Encapsulate What Varies Take what varies and “encapsulate” it so it won’t affect the rest of your code. Take what varies and “encapsulate” it so it won’t affect the rest of your code.  In other words, identify the aspects that vary and separate them from what stays the same.  Results in fewer unintended consequences from code changes.  Decouples components that change frequently from those that are relatively stable.  Changes become much less limited in scope and aren’t as invasive.  Engenders modularity and flexibility.

35 Encapsulate What Varies Data Encapsulation Typical Example – The JavaBean Typical Example – The JavaBean  Define private members  Encapsulate access to private members by creating accessors and mutators (getters and setters).  Eclipse provide a refactoring function to easily encapsulate class fields.

36 Encapsulate What Varies Procedural Encapsulation Identify what varies and hide it behind an interface – Implementations of the interface can vary without violating the contract of the interface. Identify what varies and hide it behind an interface – Implementations of the interface can vary without violating the contract of the interface.  This is the essence of the OO concept - “Abstraction”. Abstraction focuses on the outside view of an object and separates an object’s behavior from its implementation.  Dependency Inversion Principle - Abstractions should not depend on details. Details should depend on Abstractions.

37 Encapsulate What Varies The “Encapsulate What Varies” principle forms the basis for most design patterns. For example… The “Encapsulate What Varies” principle forms the basis for most design patterns. For example…  Factory - Code that creates objects is generally subject to frequent change. Use the Factory pattern to encapsulate object creation.  State - The State pattern allows an object to vary its behavior when its internal state changes. Each state is generally encapsulated in its own class.  Strategy - Encapsulates each algorithm in a family of algorithms so that they can vary for each client that uses them.


Download ppt "Lecture 16 Composition vs Inheritance: The Final Chapter."

Similar presentations


Ads by Google