37
1 Computer Science 340 Software Design & Testing Inheritance

1 Computer Science 340 Software Design & Testing Inheritance

Embed Size (px)

Citation preview

Page 1: 1 Computer Science 340 Software Design & Testing Inheritance

1

Computer Science 340

Software Design & Testing

Inheritance

Page 2: 1 Computer Science 340 Software Design & Testing Inheritance

2

Class reuse• Two forms of class reuse:

– Class inheritance– Object composition

A

B

AB

Inheritance

Composition

Page 3: 1 Computer Science 340 Software Design & Testing Inheritance

3

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

A

B

Page 4: 1 Computer Science 340 Software Design & Testing Inheritance

4

Class Inheritance

A

B

• Inheritance establishes a subtyping relationship with 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

Page 5: 1 Computer Science 340 Software Design & Testing Inheritance

5

Inheritance-based reuse example• Microsoft Foundation Classes (MFC)

• Visual Studio generates code for a functional Windows application

• MFC base classes provide a lot of standard Windows functionality, and define specific integration points for app-specific code

• Subclasses provide app-specific functionality

MFCDocumentMFCViewMFCApplication

NetworkWindowNetworkApplication NetworkDocumentDiscoveryView

1..* 11 *

MFCWindow

1 1

BrowseView TopologyView

Page 6: 1 Computer Science 340 Software Design & Testing Inheritance

6

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

AB

Page 7: 1 Computer Science 340 Software Design & Testing Inheritance

7

Composition-based reuse example

• Order Shipper

OrderShipper

FedExShipper

UPSShipper

USMailShipper

Page 8: 1 Computer Science 340 Software Design & Testing Inheritance

8

Choosing between Composition and Inheritance

• What type of relationship is being modeled?– B “has-a” A => composition– B “uses-a” A => composition– B “is-a” A => inheritance (usually)

Page 9: 1 Computer Science 340 Software Design & Testing Inheritance

9

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

Page 10: 1 Computer Science 340 Software Design & Testing Inheritance

10

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 Eclipse has a handy “Generate

Delegate Methods” option for exposing delegate features if you’re using composition

Page 11: 1 Computer Science 340 Software Design & Testing Inheritance

11

Choosing between Composition and Inheritance

• Dynamic “is-a” relationships should be implemented using composition

– Inheritance represents a static relationship between two classes that cannot be changed at runtime

– Composition relationships can be changed at runtime (more flexible than inheritance)

Page 12: 1 Computer Science 340 Software Design & Testing Inheritance

12

Choosing between Composition and Inheritance

• Dynamic “is-a” relationships should be implemented using composition

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

person has been created, their vocation cannot changePerson

Engineer Doctor Lawyer SalesPerson

Page 13: 1 Computer Science 340 Software Design & Testing Inheritance

13

Choosing between Composition and Inheritance

• Dynamic “is-a” relationships should be implemented using composition

• Example: Vocations– This design uses a combination of composition and

inheritance to allow a person’s vocation to change over their lifetime

Vocation

Engineer Doctor Lawyer SalesPerson

Person

Page 14: 1 Computer Science 340 Software Design & Testing Inheritance

14

Choosing between Composition and Inheritance

• Another example of a dynamic “is-a” relationship

Employee

CommissionedEmployee

SalariedEmployee

HourlyEmployee

CommissionedEmployee

SalariedEmployee

HourlyEmployee

PaymentClassification

Employee

Page 15: 1 Computer Science 340 Software Design & Testing Inheritance

15

Choosing between Composition and Inheritance

• Multi-valued “is-a” relationships should also be implemented using composition– i.e., each instance can be a member of multiple

subclasses– Example: Test Tracker users can have multiple roles

User

Test Manager Dev Manager Administrator Tester Developer

Page 16: 1 Computer Science 340 Software Design & Testing Inheritance

16

Choosing between Composition and Inheritance

• Multi-valued “is-a” relationships should also be implemented using composition– Could create a subclass for every possible combination– Doesn’t scale, and won’t work if relationship is both

multi-valued and dynamicUser

Test Manager Dev Manager Administrator Tester Developer

TesterDeveloperAdministratorTester AdministratorDeveloperAdministratorTesterDeveloper ......

Page 17: 1 Computer Science 340 Software Design & Testing Inheritance

17

Choosing between Composition and Inheritance

• Multi-valued “is-a” relationships should also be implemented using composition– Example: Use a combination of composition and

inheritance

Role

Test Manager Dev Manager Administrator Tester Developer

User

* 1..*

Page 18: 1 Computer Science 340 Software Design & Testing Inheritance

18

Specialization: a set-based perspective• A class is a “set of instances”• A class’ instances share some common properties and

operations

A

Page 19: 1 Computer Science 340 Software Design & Testing Inheritance

19

Specialization: a set-based perspective• A “specialization” of a class is a subset of its

instances that have even more properties and operations in common

A

X

Page 20: 1 Computer Science 340 Software Design & Testing Inheritance

20

Specialization: a set-based perspective• Example: Dog is a specialization of Animal

– In addition to all Animal features, Dogs also have a bark operation

• Example: Rectangle is a specialization of Polygon– In addition to all Polygon features, Rectangles also have a

diagonal property

Animal

Dog

Page 21: 1 Computer Science 340 Software Design & Testing Inheritance

21

Specialization: a set-based perspective• Specialization is frequently implemented using

inheritance

A

X

Y

Z

A

X Y Z

Page 22: 1 Computer Science 340 Software Design & Testing Inheritance

22

Specialization: a set-based perspective• If instances can move between specializations at runtime,

composition must be used because inheritance relationships are static (i.e., dynamic “is-a” relationships)

A

X

Y

ZX Y Z

A

Page 23: 1 Computer Science 340 Software Design & Testing Inheritance

23

Specialization: a set-based perspective• If instances can be members of multiple specializations at the

same time, composition should be used (i.e., multi-valued “is-a” relationships)

A

X

Y

ZX Y Z

A

* 1..*

Page 24: 1 Computer Science 340 Software Design & Testing Inheritance

24

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”

• To reduce this coupling, the “subclass interface” between a base class and its subclasses should be carefully designed

• Some 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)

• Information hiding is still a good practice, even between super- and sub-classes

Page 25: 1 Computer Science 340 Software Design & Testing Inheritance

25

Designing the subclass interface

• Subclasses need to:

– Access base class features in ways not available through the public interface

– Specialize base class behavior

Public Interface

Subclass Interface

Base Class

Sub Class

Client Client

Page 26: 1 Computer Science 340 Software Design & Testing Inheritance

26

Designing the subclass interface

• Base classes should keep their variables private when possible

• Base classes should 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 very good reason to do so (other than being in a hurry)

Public Interface

Subclass Interface

Base Class

Sub Class

Client Client

Page 27: 1 Computer Science 340 Software Design & Testing Inheritance

27

Designing the subclass interface• Keep methods private when

subclasses don’t need to access or override them

• Base classes should define polymorphic methods for aspects of their behavior that subclasses can specialize

– Virtual methods in C++– All 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

– Non-virtual methods in C++– “final” methods in Java

Public Interface

Subclass Interface

Base Class

Sub Class

Client Client

Page 28: 1 Computer Science 340 Software Design & Testing Inheritance

28

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)

Public Interface

Subclass Interface

Base Class

Sub Class

Client Client

Page 29: 1 Computer Science 340 Software Design & Testing Inheritance

29

Subclass interface examples

• Logger class

• Test Tracker Base Panel class– see Javadocs for a description of

BasePanel’s subclass interface

Page 30: 1 Computer Science 340 Software Design & Testing Inheritance

30

Patterns for designing the subclass interface

• Template Method pattern

• Factory Method pattern

Page 31: 1 Computer Science 340 Software Design & Testing Inheritance

31

Template Method pattern• Common Wisdom: 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

Page 32: 1 Computer Science 340 Software Design & Testing Inheritance

32

/** * 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 playersCount; abstract void initializeGame(); abstract void makePlay(int player); abstract boolean endOfGame(); abstract void printWinner(); /* A template method : */ public final void playOneGame(int playersCount) { this.playersCount = playersCount; initializeGame(); int j = 0; while (!endOfGame()) { makePlay(j); j = (j + 1) % playersCount; } printWinner(); }}

//Now we can extend this class in order //to implement actual games: class Monopoly extends Game { /* Implementation of necessary concrete methods */ void initializeGame() { // Initialize players // Initialize money } void makePlay(int player) { // Process one turn of player } boolean endOfGame() { // Return true if game is over // according to Monopoly rules } void printWinner() { // Display who won } /* Specific declarations for the Monopoly game. */ // ...}

Page 33: 1 Computer Science 340 Software Design & Testing Inheritance

33

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 doesn’t know the concrete class of the object it needs, so it can’t call new

– Instantiation of the object is delegated to sub-classes, which do know which concrete class to instantiate

Page 34: 1 Computer Science 340 Software Design & Testing Inheritance

Factory Method Pattern

34

Page 35: 1 Computer Science 340 Software Design & Testing Inheritance

35

interface Vehicle{  public void drive();  public void clean();}class Car implements Vehicle{  @Override  public void drive(){    System.out.println("Driving a car...");  }     @Override  public void clean(){    System.out.println("Cleaning a car...");  }}class Bus implements Vehicle{  @Override  public void drive(){    System.out.println("Driving a Bus...");  }     @Override  public void clean(){    System.out.println("Cleaning a Bus...");  }}

abstract class VehicleDriver{  public abstract Vehicle getVehicle();  public void driveVehicle(){    getVehicle().drive();  }  public void cleanVehicle(){    getVehicle().clean();  }}class CarDriver extends VehicleDriver{  @Override  public Vehicle getVehicle(){    return new Car();  }} class BusDriver extends VehicleDriver{  @Override  public Vehicle getVehicle(){    return new Bus();  }}

Page 36: 1 Computer Science 340 Software Design & Testing Inheritance

36

public class FactoryMethodPattern {   public static void main(String[] args) {         handleVehicle(new CarDriver());    handleVehicle(new BusDriver());  }  static void handleVehicle(VehicleDriver2 vDriver){    System.out.println("Handling a new vehicle.");    vDriver.driveVehicle();    vDriver.cleanVehicle();  }}

Handling a new vehicle. Driving a car...Cleaning a car...Handling a new vehicle. Driving a Bus...Cleaning a Bus...

Page 37: 1 Computer Science 340 Software Design & Testing Inheritance

37

public class MazeGame { public MazeGame() { Room room1 = makeRoom(); Room room2 = makeRoom(); room1.connect(room2); this.addRoom(room1); this.addRoom(room2); } protected Room makeRoom() { return new OrdinaryRoom(); }}

public class MagicMazeGame extends MazeGame { @Override protected Room makeRoom() { return new MagicRoom(); }}