Computer Science 340 Software Design Testing Inheritance Template

  • Slides: 29
Download presentation
Computer Science 340 Software Design & Testing Inheritance Template Method Pattern Factory Method Pattern

Computer Science 340 Software Design & Testing Inheritance Template Method Pattern Factory Method Pattern 1

Class Reuse • Two forms of class reuse: – Class implementation inheritance • “extends”

Class Reuse • Two forms of class reuse: – Class implementation inheritance • “extends” in Java • Different than “implements”, which is “interface inheritance” – Object composition 2

Class Inheritance • This class is like that class except for these differences …

Class Inheritance • This class is like that class except for these differences … – Specialize superclass behavior by overriding methods • • – Totally replace a superclass operation Add pre/post processing before/after superclass operation Extend superclass by adding new variables/operations 3

Class Inheritance • Inheritance establishes a subtyping relationship between subclass and superclass, thus enabling

Class Inheritance • Inheritance establishes a subtyping relationship between subclass and superclass, thus enabling polymorphism – Polymorphism = Subtyping + Dynamic method binding – Subclass instances may be used anywhere superclass instances are expected • Liskov Substitution Principle 4

Object Composition • Client class creates an internal instance of existing class and invokes

Object Composition • Client class creates an internal instance of existing class and invokes its functionality through regular method calls • Generally results in looser coupling than the inheritance relationship – With inheritance, changes to A are more likely to break B than with composition • No subtyping relationship is established between the two classes, thus preventing polymorphism • Extra levels of indirection in method calls can reduce efficiency, but this usually isn’t a problem 5

Choosing Between Composition Inheritance • What type of relationship is being modeled? – B

Choosing Between Composition Inheritance • What type of relationship is being modeled? – B “has-a” A => composition – B “uses” A => composition – B “is-a” A => inheritance • Specialization 6

Choosing Between Composition and Inheritance • “Favor object composition over class inheritance. ” [Design

Choosing Between Composition and Inheritance • “Favor object composition over class inheritance. ” [Design Patterns, pg. 20] • Composition is: – More flexible than inheritance – Leads to lower coupling than inheritance – Allows control over which delegate features are exposed, and what the API looks like – Often more complex than inheritance 7

Choosing Between Composition and Inheritance • Inheritance: – Supports polymorphism, while composition does not

Choosing Between Composition and Inheritance • Inheritance: – Supports polymorphism, while composition does not – Is easier if you want to expose many of the superclass’ features • Although Intellij and Eclipse both have a handy “Generate Delegate Methods” option for exposing delegate features if you’re using composition 8

Dynamic Inheritance • Dynamic inheritance is when you have objects that change class over

Dynamic Inheritance • Dynamic inheritance is when you have objects that change class over time • Dynamic inheritance can be implemented using a combination of composition and interface inheritance 9

Dynamic Inheritance • Example: Vocations – This inheritance-based design is inflexible because once a

Dynamic Inheritance • Example: Vocations – This inheritance-based design is inflexible because once a person has been created, their vocation cannot change 10

Dynamic Inheritance • Example: Vocations – This design uses a combination of composition (with

Dynamic Inheritance • Example: Vocations – This design uses a combination of composition (with delegation) and interface inheritance to allow a person’s vocation to change over their lifetime 11

Dynamic Inheritance • Another example of dynamic inheritance 12

Dynamic Inheritance • Another example of dynamic inheritance 12

Multiple Inheritance • Multiple inheritance is when an object is a member of multiple

Multiple Inheritance • Multiple inheritance is when an object is a member of multiple classes at once 13

Multiple Inheritance • What if you need multiple inheritance, but your programming language does

Multiple Inheritance • What if you need multiple inheritance, but your programming language does not support it (like Java)? • This design uses a combination of composition and interface inheritance to allow a Phd. Student to be both an Instructor and a Student • Phd. Student delegates method calls to Instructor and Student 14

Multiple Inheritance • Hybrid approach • Use implementation inheritance for one super-class, and interface

Multiple Inheritance • Hybrid approach • Use implementation inheritance for one super-class, and interface inheritance + composition for the other super-classes • Which one should I use for implementation inheritance? The one that most closely matches the ”is-a” rule. 15

Inheritance-Based Reuse • Inheritance is a more tightly coupled relationship than composition – Inheritance

Inheritance-Based Reuse • Inheritance is a more tightly coupled relationship than composition – Inheritance is sometimes called “white box reuse”, and composition is called “black box reuse” • Unwise programmers, when they realize they need to subclass an existing class, make all the “private” features “protected”, make all the methods “virtual”, and say, “There, now it’s a base class!”. • This approach results in extremely high coupling between a base class and its subclasses, and results in a fragile base class (i. e. , a base class that is difficult to change without breaking its subclasses) • To minimize coupling, the “subclass interface” between a base class and its subclasses should be carefully designed • Information hiding is still a good practice, even between super- and sub -classes 16

Designing the Subclass Interface • Subclasses need to: – Access base class features in

Designing the Subclass Interface • Subclasses need to: – Access base class features in ways not available through the public interface – Specialize base class behavior Client Public Interface Base Class Subclass Interface Sub Class 17

Designing the Subclass Interface • Base classes should typically keep their variables private, and

Designing the Subclass Interface • Base classes should typically keep their variables private, and provide protected methods that allow subclasses to access or modify their state only in necessary, controlled ways • Make a variable protected only if there is a good reason to do so Client Public Interface Base Class Subclass Interface Sub Class 18

Designing the Subclass Interface • Keep methods private when subclasses don’t need to access

Designing the Subclass Interface • Keep methods private when subclasses don’t need to access or override them Client • Base classes should define polymorphic methods for aspects of their behavior that subclasses can specialize Public Interface – Virtual methods in C++ – All non-final methods in Java • Make a method polymorphic only if you expect subclasses to specialize it • Specifically prevent specialization of methods that subclasses should not override Base Class Subclass Interface Sub Class – Non-virtual methods in C++ – “final” methods in Java 19

Designing the Subclass Interface • Keeping the subclass interface as simple as possible has

Designing the Subclass Interface • Keeping the subclass interface as simple as possible has two positive outcomes: – There is more freedom to change the internal implementation of the base class without breaking subclasses (i. e. , base classes are less fragile) – It is easier for subclass authors to understand how to specialize the base class (i. e. , they have less freedom, but more guidance) Client Public Interface Base Class Subclass Interface Sub Class 20

Patterns for Designing the Subclass Interface • Template Method pattern • Factory Method pattern

Patterns for Designing the Subclass Interface • Template Method pattern • Factory Method pattern 21

Template Method Pattern • Code that is duplicated in multiple places should be centralized

Template Method Pattern • Code that is duplicated in multiple places should be centralized in one place (i. e. , avoid duplication) – Composition: Put common code in a method on a class to which multiple clients will delegate – Inheritance: Put the common code in a method on a super-class, and make the clients sub-classes (i. e. , clients inherit common code) • What if an algorithm is duplicated in several places, but the copies are SIMILAR rather than IDENTICAL? • Use the Template Method pattern – Put the common algorithm in a super-class – Clients inherit common code from super-class – Some steps of the algorithm are delegated to subclasses through polymorphic method calls – Subclasses customize the algorithm by implementing the delegated steps 22

Template Method Pattern 23

Template Method Pattern 23

/** * An abstract class that is common to several games in * which

/** * An abstract class that is common to several games in * which players play against the others, but only one is * playing at a given time. */ abstract class Game { protected int players. Count; /* A template method : */ public final void play. One. Game(int players. Count) { this. players. Count = players. Count; initialize. Game(); int j = 0; while (!end. Of. Game()) { make. Play(j); j = (j + 1) % players. Count; } print. Winner(); } abstract void initialize. Game(); abstract void make. Play(int player); abstract boolean end. Of. Game(); abstract void print. Winner(); } //Now we can extend this class in order //to implement actual games: class Monopoly extends Game { /* Specific declarations for the Monopoly game. */ /* Implementation of abstract methods */ void initialize. Game() { // Initialize players // Initialize money } void make. Play(int player) { // Process one turn of player } boolean end. Of. Game() { // Return true if game is over // according to Monopoly rules } void print. Winner() { // Display who won } /* Specific methods for the Monopoly game. */ //. . . } 24

Refactoring with the Template Method Pattern 1. Make the similar code as similar as

Refactoring with the Template Method Pattern 1. Make the similar code as similar as possible in the classes that duplicate it – 2. 3. 4. Create a common base class for all classes with similar code Put one copy of the similar code/method(s) in the parent (this becomes the template method) Identify and extract what needs to vary by subclass – – 5. 6. Similar code diverges unnecessarily over time Create abstract methods for the code that needs to vary Replace the code that needs to vary with calls to the abstract methods in the template method Override the abstract methods in the subclasses with their version of the varying code (pulled out of their copy of the template method override(s)) Delete the template method override(s) in the subclasses 25

Factory Method Pattern • Factory Method pattern – A super-class contains useful functionality that

Factory Method Pattern • Factory Method pattern – A super-class contains useful functionality that can be inherited by sub-classes – The super-class needs to instantiate an object to do its work, but it is a general class and has many potential uses. Therefore, it doesn’t know the concrete class of the object it needs so it can’t instantiate it – Instantiation of the object is delegated to sub-classes, which do know which concrete class to instantiate 26

Factory Method Pattern 27

Factory Method Pattern 27

interface Vehicle{ public void drive(); } class Car implements Vehicle{ @Override public void drive(){

interface Vehicle{ public void drive(); } class Car implements Vehicle{ @Override public void drive(){ System. out. println("Driving a car. . . "); } } class Bus implements Vehicle{ @Override public void drive(){ System. out. println("Driving a Bus. . . "); } } abstract class Vehicle. Driver{ public void drive. Vehicle(){ Vehicle v = make. Vehicle(); v. drive(); } public abstract Vehicle make. Vehicle(); } class Car. Driver extends Vehicle. Driver{ @Override public Vehicle make. Vehicle(){ return new Car(); } } class Bus. Driver extends Vehicle. Driver{ @Override public Vehicle make. Vehicle(){ return new Bus(); } } 28

public class Factory. Method. Pattern { public static void main(String[] args) { handle. Vehicle(new

public class Factory. Method. Pattern { public static void main(String[] args) { handle. Vehicle(new Car. Driver()); handle. Vehicle(new Bus. Driver()); } static void handle. Vehicle(Vehicle. Driver v. Driver){ System. out. println("Handling a new vehicle. "); v. Driver. drive. Vehicle(); } } Handling a new vehicle. Driving a car. . . Handling a new vehicle. Driving a Bus. . . 29