Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects...

30
Lecture 14 Lecture 14 Inheritance vs Inheritance vs Composition Composition

Transcript of Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects...

Page 1: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Lecture 14Lecture 14

Inheritance vs CompositionInheritance vs Composition

Page 2: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Inheritance vs InterfaceInheritance vs Interface

• Use Use inheritanceinheritance when two objects share a when two objects share a structure or code relationstructure or code relation Embodies the Embodies the is_ais_a relation relation Should reflect the roles of the objects Should reflect the roles of the objects

throughout the programthroughout the program

• Use an Use an interfaceinterface when they share a when they share a common behavior speccommon behavior spec

Page 3: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Abstract Classes vs InterfacesAbstract Classes vs Interfaces

• AbstractAbstract for the inheritance situation above, i.e. for the inheritance situation above, i.e. sharing code or structuresharing code or structure

• InterfacesInterfaces for sharing behavior spec, not code for sharing behavior spec, not code• Example: Consider a FrameworkExample: Consider a Framework

It provides code in the form of methods that are It provides code in the form of methods that are inherited without being overridden->code is inheritedinherited without being overridden->code is inherited

The implementation of an action listener cannot be The implementation of an action listener cannot be predicted, so no code is inherited herepredicted, so no code is inherited here

Page 4: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Inheritance and CompositionInheritance and Composition• Which to use and when?Which to use and when?• Alternative 1: Implement a Stack with inheritance Alternative 1: Implement a Stack with inheritance

from a Vectorfrom a Vector class Stack extends Vector{class Stack extends Vector{ public Object push(Object item){public Object push(Object item){ addElementAt(size()-1;}addElementAt(size()-1;} public Object pop(){return elementAtpublic Object pop(){return elementAt (size()- 1);}(size()- 1);}• Stacks can use protected members of VectorStacks can use protected members of Vector• Stacks can be used where Vectors are used as Stacks can be used where Vectors are used as

argumentsarguments• Reuse Vector methods, e.g. Reuse Vector methods, e.g. size, isEmptysize, isEmpty• What to do with unwanted Vector methods, e.g. What to do with unwanted Vector methods, e.g. removeAt()?removeAt()?

Page 5: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Inheritance and CompositionInheritance and Composition

• Now do this with Composition:Now do this with Composition:class Stack{class Stack{

private Vector theData;private Vector theData;

public Stack(){theData=new Vector();}public Stack(){theData=new Vector();}

public Object push(Object item){theData.addElement(public Object push(Object item){theData.addElement(

item); return item;}item); return item;}

• AdvantagesAdvantages Can change the implementation without any impact to Can change the implementation without any impact to

users of stacksusers of stacks Interface is narrower: we don’t need to know anything Interface is narrower: we don’t need to know anything

about Vectorsabout Vectors

Page 6: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Inheritance and CompositionInheritance and Composition

• Advantages to Composition (cont.)Advantages to Composition (cont.) There are no substitutability issuesThere are no substitutability issues

Stacks and Vectors are different typesStacks and Vectors are different types One cannot be substituted for the otherOne cannot be substituted for the other

Meaningless behavior is not exposedMeaningless behavior is not exposed Inheritance couples base and derived classInheritance couples base and derived class Changes do not ripple upwardsChanges do not ripple upwards Promotes encapsulationPromotes encapsulation Not dependent on private variablesNot dependent on private variables Can change implementation of composed objects at Can change implementation of composed objects at

run-time, not so with inheritancerun-time, not so with inheritance

Page 7: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

CompositionComposition

• Prefer it to inheritancePrefer it to inheritance• Used in Java AWTUsed in Java AWT

Uses Components and ContainersUses Components and Containers An item is a ComponentAn item is a Component A Container can contain Components and A Container can contain Components and

ContainersContainers Obtain a tree-like structure by nestingObtain a tree-like structure by nesting

• Embodied in the Composite PatternEmbodied in the Composite Pattern

Page 8: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Composite PatternComposite Pattern

• Facilitate the same treatment of composite and Facilitate the same treatment of composite and primitive objectsprimitive objects Composite object: an object that contains other objectsComposite object: an object that contains other objects E.g. lines and polygons are primitive objects, a drawing E.g. lines and polygons are primitive objects, a drawing

is composite.is composite.

• Composite methods are implemented by iterating Composite methods are implemented by iterating over the composite object, invoking the over the composite object, invoking the appropriate method for each subcomponentappropriate method for each subcomponent

Page 9: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Composite PatternComposite Pattern

• Use it whenUse it when You want to represent part-whole hierarchies of You want to represent part-whole hierarchies of

objectsobjects You want your clients to be able to ignore You want your clients to be able to ignore

differences between compisitions of objects and differences between compisitions of objects and objects themselvesobjects themselves

• BenefitsBenefits Easy to add new kinds of componentsEasy to add new kinds of components Makes clients simplerMakes clients simpler

Page 10: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Composite PatternComposite Pattern

• LiabilitiesLiabilities Hard to restrict the types of componentsHard to restrict the types of components Clients can do meaningless things to primitive Clients can do meaningless things to primitive

objects at run-timeobjects at run-time

Page 11: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

ExampleExample

• Consider a simple GUI system:Consider a simple GUI system:public class window{ Button[] buttons; TextArea[] ta; Menu[] menus; WidgetContainer[] containers;public void updateWindow(){ if (buttons != null){ for(k=0;k<buttons.length();k++) buttons[k].draw(); if (ta != null) ...}

Page 12: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Problem Problem

• If you want to add on a new kind of resource If you want to add on a new kind of resource the the update()update() method needs to be modified method needs to be modified

• Way around this is to use a uniform Way around this is to use a uniform interfaceinterface Just do Widgets and WidgetContainersJust do Widgets and WidgetContainers Now you are programming to an interfaceNow you are programming to an interface

All Widgets support the Widget interfaceAll Widgets support the Widget interface

Page 13: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Another AttemptAnother Attempt

public class window{ Widget[] widgets; WidgetContainer[] containers;public void updateWindow(){ if (widgets != null) for (k=0; k<widgets.length(); k++){ widgets[k].updateWindow(); if (containers != null) ....

Page 14: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Now Use Composite PatternNow Use Composite Pattern

Component

Button Menu widgetContainer

Page 15: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

To ObtainTo Obtain

public class window{ Component[] components; public void updateWindow(){ if (components != null) for(k=0;k<components.length();k++) components[k].updateWindow(); }}

•Bottom Line: Do not distinguish Widgets and WidgetContainers

Page 16: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Delegation in CompositionDelegation in Composition

• It is often convenient to allow a receiving It is often convenient to allow a receiving object, e.g. aobject, e.g. a Window Window, to further delegate , to further delegate certain operations to another object--its certain operations to another object--its delegatedelegate--e.g. a --e.g. a RectangleRectangle This is better than making This is better than making WindowWindow a subclass a subclass

of of RectangleRectangle, the , the WindowWindow class may reuse class may reuse the behavior of the behavior of RectangleRectangle and delegate and delegate rectangle-specific behavior to itrectangle-specific behavior to it

Page 17: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Window

area()

return Rectangle->area()

Rectangle

area()

widthheight

return width*height

Rectangle

Page 18: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

CommentsComments

• Here Here Window has_a RectangleWindow has_a Rectangle• It is easy to compare behavior at run-timeIt is easy to compare behavior at run-time• You can reuseYou can reuse Rectangle Rectangle as a black box (not as a black box (not

white-box as in inheritance) white-box as in inheritance) • You can use polymorphism to achieve dynamic You can use polymorphism to achieve dynamic

behavior--employ an interface. This is the behavior--employ an interface. This is the StrategyStrategy Design Pattern Design Pattern

• Trade-off: harder to understand, much more Trade-off: harder to understand, much more flexible than inheritanceflexible than inheritance

• Visitor uses delegationVisitor uses delegation

Page 19: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Combining Inheritance and Combining Inheritance and CompositionComposition

• Main use: simplify an inheritance hierarchyMain use: simplify an inheritance hierarchy• Not achievable everywhere, but it is very Not achievable everywhere, but it is very

powerful where you canpowerful where you can• Main example: Java Stream WrappersMain example: Java Stream Wrappers

Add capabilities to a stream by “wrapping” it in Add capabilities to a stream by “wrapping” it in another object that provides the desired another object that provides the desired capabilitiescapabilities

Makes a bigger, better version of a base classMakes a bigger, better version of a base class

Page 20: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

InputStream HierarchyInputStream Hierarchy

• InputStreamInputStream ByteArrayInputStreamByteArrayInputStream FileInputStreamFileInputStream PipedInputStreamPipedInputStream SequenceInputStreamSequenceInputStream ObjectInputStreamObjectInputStream FilterInputStreamFilterInputStream

BufferedInputStreamBufferedInputStream DataInputStreamDataInputStream

differ in the

source of

data values

Page 21: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

The Way It WorksThe Way It Works

• Start with an InputStream, i.e. try to read a Start with an InputStream, i.e. try to read a stream of bytes in sequencestream of bytes in sequence Use it polymorphicallyUse it polymorphically Add functionality, depending on your dataAdd functionality, depending on your data This new functionality is called a “wrapper”This new functionality is called a “wrapper” Just add a new and better interface to the old Just add a new and better interface to the old

one, getting/sending the result from/to the same one, getting/sending the result from/to the same place, i.e. InputStream, resp. OutputStreamplace, i.e. InputStream, resp. OutputStream

Subclassing provides the new interfaceSubclassing provides the new interface

Page 22: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

ExampleExample

• FilterFilter is a wrapper is a wrapper• Builds on Builds on InputStreamInputStream• First obtain the sequence of bytes from the First obtain the sequence of bytes from the InputStreamInputStream and then do the filtering and then do the filtering

• Use composition on the Use composition on the InputStreamInputStream

class FilterInputStream extends InputStream ... protected InputStream in; FilterInputStream(InputStream in){ this.in = in;} ...}

Page 23: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

CommentsComments

• You really have one object, many interfacesYou really have one object, many interfaces• Thus you avoid an explosion of the inheritance Thus you avoid an explosion of the inheritance

hierarchyhierarchy FilterInputStreamFilterInputStream is really just an is really just an InputStreamInputStream

with added functionalitywith added functionality If you wanted a If you wanted a DataInputStreamDataInputStream, just wrap the , just wrap the InputStreamInputStream in a in a DataInputStreamDataInputStream object object

Construct a new Construct a new DataInputStreamDataInputStream object, using the object, using the InputStreamInputStream as input to the constructor as input to the constructor

Page 24: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Important NoteImportant Note

• The primitive data-type operations of The primitive data-type operations of DataInputStreamDataInputStream cannot be included in cannot be included in InputStreamInputStream, because that object does not , because that object does not know about know about integer, floatinteger, float, etc, etc

• But you can make it understand these types by But you can make it understand these types by wrapping.wrapping.

• The neat thing: You can use a The neat thing: You can use a DataInputStreamDataInputStream anywhere an anywhere an InputStream InputStream is expected--thi is the advantage of inheritanceis expected--thi is the advantage of inheritance

Page 25: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

ExampleExample

• If If dataSourcedataSource is of type is of type InputStream:InputStream:

InputStream dataSource;InputStream dataSource;• Then the Then the DataInputStream:DataInputStream:

DataInputStream typedDataSource =DataInputStream typedDataSource =

new DataInputStream(dataSource);new DataInputStream(dataSource);• Gets the data from exactly the same place as data Gets the data from exactly the same place as data

retrieved from retrieved from dataSourcedataSource• We have merely provided a better interface to the We have merely provided a better interface to the

same input streamsame input stream

Page 26: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Another Example: Buffered Another Example: Buffered ReadersReaders

• UseUse Reader Readers and s and WriterWriters for character datas for character data• Start with primitive readers that directly manipulate the Start with primitive readers that directly manipulate the

input data:input data: CharArrayReader, StringReader, FileReaderCharArrayReader, StringReader, FileReader

• Now add functionality to data generated by the above Now add functionality to data generated by the above Readers:Readers: BufferedReader, FilterReader, BufferedReader, FilterReader, LineNumberReaderLineNumberReader

• ReaderReader has the subclasses has the subclasses BufferedReaderBufferedReader FileReaderFileReader PipedReaderPipedReader

Page 27: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

One Way to Buffer the Char InputOne Way to Buffer the Char Input

• Do it from Do it from FileReader:FileReader:

BufferedReader in =new BufferedReader in =new BufferedReader( new BufferedReader( new FileReader(“stuff.in”);FileReader(“stuff.in”);

• Buffers the char file Buffers the char file “stuff.in”“stuff.in”

Page 28: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

Another WayAnother Way

• Start with Reader (which is also primitive for Start with Reader (which is also primitive for 16 Bit Unicodes)16 Bit Unicodes)

• Buffer on top of itBuffer on top of it Allow two types of buffer--a standard one with Allow two types of buffer--a standard one with

8192 bytes and another of user-specified size8192 bytes and another of user-specified size Use Reader’s capabilities and then add the Use Reader’s capabilities and then add the

buffering in the constructorbuffering in the constructor

Page 29: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

public class BufferedReader extends Reader{ private Reader in; //use composition private char cb[]; //the buffer private static int defaultCharBufferSize=8192; private static int defaultExpectedLineLength=80; public BufferedReader(Reader in, int sz){ super(in); //get Reader functionality if (sz <= 0) throw new IllegalArgumentException( “Illegal Buffer size”); this.in = in; cb = new char[sz]; nextChar = nChars = 0;}

public BufferedReader(Reader in){ this(in, defaultCharBufferSize);}

Page 30: Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when.

RemarksRemarks

• BufferedReaderBufferedReader has methods has methods read()read() and and readLine()readLine() to read a single to read a single character, resp. a line of text.character, resp. a line of text.

• Both of these throw an Both of these throw an IOExceptionIOException• Remember to import from Remember to import from java.iojava.io