This is a set of "slides" to accompany chapter 10 of Timothy Budd's textbook Understanding Object-Oriented Programming with Java (Addison-Wesley, 1998).
In Java, substitutability by implementing interfaces as well as subclassing
Natural for dog to inherit from mammal
Not natural to use inheritance
But "a car has-a(n) engine" sounds right
Can use composition (aggregation)
Suppose already have List
data type with the following behavior:
class List { public List() { ... } public void add(int) { ... } public void remove(int) { ... } public boolean includes(int) { ... } public int firstElement() { ... } ... }
Wish to build Set
data type -- elements are unique and
unordered in set
class Set extends List { public void add(int) { ... } }
add
method overrides the one in List
List
firstElement
operation
Set
potentially substitutable for List
class Set { public Set() { ... data = new List(); ... } public void add(int) { ... } public void remove(int) { ... } public boolean includes(int) { return data.includes(int); } private List data; }
List
firstElement()
List
operations on data
field
Set
not substitutable for List
Java API class InputStream
ByteArrayInputStream
FileInputStream
PipedInputStream
SequenceInputStream
StringBufferInputStream
InputStream
component
FilterInputStream
InputStream
of any type
InputStream
An advantage of composition over inheritance is delay in binding time -- parent/child inheritance at compile time
class Frog { public Frog() { behavior = new TadpoleBehavior(); } public grow() // see if behavior should change { if (behavior.growUp()) { behavior = new AdultFrogBehavor(); } behavior.grow(); // behavior does actual work behavior.swim(); } private FrogBehavior behavior; } abstract class FrogBehavior { public void grow(); public void swim(); public boolean growUp() { return false; } } class TadpoleBehavior extends FrogBehavior { public void grow() { ... } public void swim() { ... } public boolean growUp() { age++; return (age > 24); } private int age = 0; } class AdultFrogBehavior extends FrogBehavior { public void grow() { ... } public void swim() { ... } }
Frog
delegates its work to component
FrogBehavior
object
behavior
holds
current FrogBehavior
object
FrogBehavior
classes for differing
behaviors (tadpole or adult)
Frog
object modifies behavior
component
when change needed (from tadpole to adult at proper age)
grow()
and
swim()
methods called for current stage
Frog
object (interface) unchanged throughout life,
but actual behavior changed as needed
Even with the right mechanisms, software reuse not guaranteed to occur
Also need the right culture:
UP to CSCI 581 Lecture Notes root document?