Inheritance Principles of Software System Construction Principles - - PowerPoint PPT Presentation

inheritance
SMART_READER_LITE
LIVE PREVIEW

Inheritance Principles of Software System Construction Principles - - PowerPoint PPT Presentation

Inheritance Principles of Software System Construction Principles of Software System Construction Jonathan Aldrich Bill Scherlis Spring 2012 Bank Accounts What kind of accounts does a bank offer? What are their basic features? Fall 2011


slide-1
SLIDE 1

Inheritance

Principles of Software System Construction Principles of Software System Construction Jonathan Aldrich Bill Scherlis Spring 2012

slide-2
SLIDE 2

Bank Accounts

What kind of accounts does a bank offer? What are their basic features?

Fall 2011 15-214: Course Introduction 2

slide-3
SLIDE 3

Account Interfaces

«interface» CheckingAccount getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean getFee() : float «interface» SavingsAccount getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean getInterestRate() : float

What do you think of this design?

Fall 2011 15-214: Course Introduction 3

getFee() : float getInterestRate() : float

slide-4
SLIDE 4

Account Type Hierarchy

«interface» Account getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment() SavingsAccount is a subtype of

  • Account. Account

is a supertype of SavingsAccount. CheckingAccount extends Account. All methods from Account are inherited (copied to CheckingAccount)

Fall 2011 15-214: Course Introduction 4

«interface» CheckingAccount getFee() : float «interface» SavingsAccount getInterestRate() : float «interface» InterestCheckingAccount Multiple interface extension If we know we have a CheckingAccount, additional methods are available.

slide-5
SLIDE 5

The Power of Object-Oriented Interfaces

  • Polymorphism

Different kinds of objects can be treated uniformly by clients

Keep a list of all accounts Use accessor (getBalance) and mutator (deposit, transfer) methods

Each object behaves according to its type

monthlyAdjustment(): fee for checking, interest for savings

void adjustAll() { void adjustAll() { for (Account acct : getAllAccounts()) acct.monthlyAdjustment() }

  • Impact

Add new kind of account: client code does not change Important because this kind of change happens often!

Fall 2011 15-214: Course Introduction 5

Polymorphism is the key strength of OO Difficult to encode in other paradigms and languages (C, ML, etc.) Will come back repeatedly in this class

slide-6
SLIDE 6

Implementing Accounts

  • All 3 accounts similar

Same code for balance, deposit, withdraw, transfer Differ in monthlyAdjustment Differ in additional features

  • Duplication is bad

«interface» Account getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment()

  • Duplication is bad

Lots of code to type Fix bugs 3 times Make enhancements 3 times Easily becomes inconsistent What if another new account type is developed?

  • Design mantra: once and only
  • nce!

Fall 2011 15-214: Course Introduction 6

«interface» CheckingAccount getFee() : float «interface» SavingsAccount getInterestRate() : float «interface» InterestCheckingAccount

slide-7
SLIDE 7

Reusing Account Code

public abstract class AbstractAccount implements Account { protected float balance = 0.0; public float getBalance() { return balance; } abstract public void monthlyAdjustment(); // other methods…

«interface» Account getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment() AbstractAccount

protected elements are visible in subclasses an abstract class is missing the implemention of one

  • r more methods

} public class CheckingAccountImpl extends AbstractAcount implements CheckingAccount { public void monthlyAdjustment() { balance -= getFee(); } public float getFee() { /* fee calculation */ } }

Fall 2011 15-214: Course Introduction 7

CheckingAccountImpl monthlyAdjustment() getFee() : float AbstractAccount # balance : float + getBalance() : float + deposit(amount : float) + withdraw(amount : float) : boolean + transfer(amount : float, target : Account) : boolean + monthlyAdjustment() «interface» CheckingAccount getFee() : float

an abstract method is left to be implemented in a subclass no need to define getBalance() – the code is inherited from AbstractAccount

slide-8
SLIDE 8

Inheritance vs. Subtyping

  • Inheritance

A class reuses code from a superclass

class A extends B

Inheritance is for code reuse

Write code once and only once Code from superclass implicitly available in subclass

  • Subtyping

A class implements a (Java) interface

class A implements I

A class implements the (implicit) interface of another class

class A extends B : both subtyping and inheritance

Subtyping is for polymorphism

Accessing objects the same way, but getting different behavior Subtype is substitutable for supertype

Fall 2011 15-214: Course Introduction 8

slide-9
SLIDE 9

Challenge: Is Inheritance Necessary?

Can we get the same amount of code reuse using only interfaces?

«interface» Account getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment()

Fall 2011 15-214: Course Introduction 9

«interface» CheckingAccount getFee() : float «interface» SavingsAccount getInterestRate() : float «interface» InterestCheckingAccount

slide-10
SLIDE 10

Reuse via Wrapping

«interface» Account getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment()

requires a lot of forwarding

Fall 2011 15-214: Course Introduction 10

«interface» CheckingAccount getFee() : float CheckingAccountImpl monthlyAdjustment() { … } getFee() : float { … } getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean

basicAcnt .getBalance()

BasicAccountImpl balance : float getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean

basicAcnt

slide-11
SLIDE 11

Reuse via Wrapping, version 2

«interface» Account getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment()

adjustment account

requires two-way dependence

Fall 2011 15-214: Course Introduction 11

«interface» Adjustment doAdjust() SavingsAccountAdjustment doAdjust()

adjustment .doAdjust()

BasicAccountImpl balance : float getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment()

adjustment account float bal = account.getBalance(); float interest = bal * interestRate; account.deposit(interest);

slide-12
SLIDE 12

Inheritance vs. Delegation

The wrapping strategy described above is called delegation Delegation can be cleaner than inheritance

Reused code in a separate object Interfaces between objects

However, inheritance eliminates boilerplate

Forwarding functions Forwarding functions Recursive dependencies

Fall 2011 15-214: Course Introduction 12

slide-13
SLIDE 13

Overloading

When an object has multiple methods with the same name but different argument types Who can name an example? Why would anyone do this?

Fall 2011 15-214: Course Introduction 13

slide-14
SLIDE 14

Method dispatch, revisited

Example call: x.foo(5);

  • Step 1 (compile time): determine what class to look in

Look at the static type of the receiver (x in the example above)

  • Step 2 (compile time): determine the method signature

Find all methods in the class with the right name

Includes inherited methods Includes inherited methods

Keep only methods that are accessible

E.g. a private method is not accessible to calls from outside the class

Keep only methods that are applicable

The types of the actual arguments (e.g. 5 has type int above) must be subtypes

  • f the corresponding formal parameter type

Select the most specific method

m1 is more specific than m2 if each argument of m1 is a subtype of the corresponding argument of m2

Keep track of the method’s signature (argument types) for run-time

Fall 2011 14 15-214: Course Introduction

slide-15
SLIDE 15

Method dispatch, revisited

Step 3 (run time): Determine the run-time class of the receiver

Look at the object in the heap to find out what its run-time class is

Step 4 (run time): Locate the method to invoke

Starting at the run-time class, look for a method with the right name and argument types that are identical to those in the method found and argument types that are identical to those in the method found statically (step 2) If it is found in the run-time class, invoke it. Otherwise, continue the search in the superclass of the run-time class This procedure will always find a method to invoke, due to the checks done during static typechecking

Fall 2011 15-214: Course Introduction 15

slide-16
SLIDE 16

Extending methods with super

public abstract class AbstractAccount implements Account { protected float balance = 0.0; public boolean withdraw(float amount) { if (amount > balance) return false; balance -= amount; return true; } /* other methods… */ } /* other methods… */ } public class ExpensiveCheckingAccountImpl extends AbstractAcount implements CheckingAccount { public boolean withdraw(float amount) { boolean success = super.withdraw(amount) if (success) balance -= ATM_FEE; return success; } /* other methods… */ }

Fall 2011 15-214: Course Introduction 16

invokes a method on this, but starts dispatch in superclass for this call only.

slide-17
SLIDE 17

Constructor calls

public class CheckingAccountImpl extends AbstractAcount implements CheckingAccount { private float fee; public CheckingAccountImpl(float initialBalance, float fee) { super(initialBalance);

invokes a particular

super(initialBalance); this.fee = fee; } public CheckingAccountImpl(float initialBalance) { this(initialBalance, 5.00); } /* other methods… */ }

Fall 2011 15-214: Course Introduction 17

invokes another constructor in the same class invokes a particular constructor of the

  • superclass. Must be

the first statement of the constructor.

slide-18
SLIDE 18

Inheritance Details: final

When modifying a class: cannot extend the class When modifying a method: cannot override the method When modifying a field: cannot assign to the field

  • ther than initialization in the constructor

Why might you want to use final in each of the above cases?

Fall 2011 15-214: Course Introduction 18

slide-19
SLIDE 19

Inheritance Details: instanceof

  • Operator that tests whether an object is of a given class

DataInput input = …; if (input instanceof ObjectInput)

  • bj = input.readObject();
  • Guidelines for use

OK to find out which case of a datatype you have

Choice among conceptually different abstractions Choice among conceptually different abstractions

  • Cf. datatypes in ML

DON’T use to choose among implementations of an abstraction

Implementation choices are supposed to be hidden

  • instanceof examples: good or bad?

Test if an object is Serializable Test if a List is an ArrayList Test if a TreeNode is an InternalNode or a LeafNode Test if a InputStream is a FileInputStream

Fall 2011 15-214: Course Introduction 19

slide-20
SLIDE 20

Aside: UML class diagram notation

«interface» Account getBalance() : float deposit(amount : float) withdraw(amount : float) : boolean transfer(amount : float, target : Account) : boolean monthlyAdjustment() AbstractAccount

«interface» brand Name of class or interface in top compartment Return type comes after method or field Methods in bottom compartment Dashed line, open triangle arrowhead for implements

Fall 2011 15-214: Course Introduction 20

AbstractAccount # balance : float + getBalance() : float + deposit(amount : float) + withdraw(amount : float) : boolean + transfer(amount : float, target : Account) : boolean + monthlyAdjustment() CheckingAccountImpl monthlyAdjustment() getFee() : float

Solid line, open triangle arrowhead for extends Italics means abstract Italics means abstract Optional visibility: + for public

  • for private

# for protected ~ for package (not used much) Fields in middle compartment