Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when."— Presentation transcript:

1 Lecture 14 Inheritance vs Composition

2 Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when two objects share a structure or code relation  Embodies the is_a relation  Should reflect the roles of the objects throughout the program Use an interface when they share a common behavior spec Use an interface when they share a common behavior spec

3 Abstract Classes vs Interfaces Abstract for the inheritance situation above, i.e. sharing code or structure Abstract for the inheritance situation above, i.e. sharing code or structure Interfaces for sharing behavior spec, not code Interfaces for sharing behavior spec, not code Example: Consider a Framework Example: Consider a Framework  It provides code in the form of methods that are inherited without being overridden->code is inherited  The implementation of an action listener cannot be predicted, so no code is inherited here

4 Inheritance and Composition Which to use and when? Which to use and when? Alternative 1: Implement a Stack with inheritance from a Vector Alternative 1: Implement a Stack with inheritance from 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 elementAt public Object pop(){return elementAt (size()- 1);} (size()- 1);} Stacks can use protected members of Vector Stacks can use protected members of Vector Stacks can be used where Vectors are used as arguments Stacks can be used where Vectors are used as arguments Reuse Vector methods, e.g. size, isEmpty Reuse Vector methods, e.g. size, isEmpty What to do with unwanted Vector methods, e.g. removeAt()? What to do with unwanted Vector methods, e.g. removeAt()?

5 Inheritance and Composition Now do this with Composition: Now do this with Composition: class Stack{ 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;} Advantages Advantages  Can change the implementation without any impact to users of stacks  Interface is narrower: we don’t need to know anything about Vectors

6 Inheritance and Composition Advantages to Composition (cont.) Advantages to Composition (cont.)  There are no substitutability issues  Stacks and Vectors are different types  One cannot be substituted for the other  Meaningless behavior is not exposed  Inheritance couples base and derived class  Changes do not ripple upwards  Promotes encapsulation  Not dependent on private variables  Can change implementation of composed objects at run-time, not so with inheritance

7 Composition Prefer it to inheritance Prefer it to inheritance Used in Java AWT Used in Java AWT  Uses Components and Containers  An item is a Component  A Container can contain Components and Containers  Obtain a tree-like structure by nesting Embodied in the Composite Pattern Embodied in the Composite Pattern

8 Composite Pattern Facilitate the same treatment of composite and primitive objects Facilitate the same treatment of composite and primitive objects  Composite object: an object that contains other objects  E.g. lines and polygons are primitive objects, a drawing is composite. Composite methods are implemented by iterating over the composite object, invoking the appropriate method for each subcomponent Composite methods are implemented by iterating over the composite object, invoking the appropriate method for each subcomponent

9 Composite Pattern Use it when Use it when  You want to represent part-whole hierarchies of objects  You want your clients to be able to ignore differences between compisitions of objects and objects themselves Benefits Benefits  Easy to add new kinds of components  Makes clients simpler

10 Composite Pattern Liabilities Liabilities  Hard to restrict the types of components  Clients can do meaningless things to primitive objects at run-time

11 Example 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)... }

12 Problem If you want to add on a new kind of resource the update() method needs to be modified If you want to add on a new kind of resource the update() method needs to be modified Way around this is to use a uniform interface Way around this is to use a uniform interface  Just do Widgets and WidgetContainers  Now you are programming to an interface  All Widgets support the Widget interface

13 Another 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)....

14 Now Use Composite Pattern Component ButtonMenuwidgetContainer

15 To 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

16 Delegation in Composition It is often convenient to allow a receiving object, e.g. a Window, to further delegate certain operations to another object--its delegate--e.g. a Rectangle It is often convenient to allow a receiving object, e.g. a Window, to further delegate certain operations to another object--its delegate--e.g. a Rectangle  This is better than making Window a subclass of Rectangle, the Window class may reuse the behavior of Rectangle and delegate rectangle-specific behavior to it

17 Window area() return Rectangle->area() Rectangle area() width height return width*height Rectangle

18 Comments Here Window has_a Rectangle Here Window has_a Rectangle It is easy to compare behavior at run-time It is easy to compare behavior at run-time You can reuse Rectangle as a black box (not white-box as in inheritance) You can reuse Rectangle as a black box (not white-box as in inheritance) You can use polymorphism to achieve dynamic behavior--employ an interface. This is the Strategy Design Pattern You can use polymorphism to achieve dynamic behavior--employ an interface. This is the Strategy Design Pattern Trade-off: harder to understand, much more flexible than inheritance Trade-off: harder to understand, much more flexible than inheritance Visitor uses delegation Visitor uses delegation

19 Combining Inheritance and Composition Main use: simplify an inheritance hierarchy Main use: simplify an inheritance hierarchy Not achievable everywhere, but it is very powerful where you can Not achievable everywhere, but it is very powerful where you can Main example: Java Stream Wrappers Main example: Java Stream Wrappers  Add capabilities to a stream by “wrapping” it in another object that provides the desired capabilities  Makes a bigger, better version of a base class

20 InputStream Hierarchy InputStream InputStream  ByteArrayInputStream  FileInputStream  PipedInputStream  SequenceInputStream  ObjectInputStream  FilterInputStream  BufferedInputStream  DataInputStream  differ in the source of data values

21 The Way It Works Start with an InputStream, i.e. try to read a stream of bytes in sequence Start with an InputStream, i.e. try to read a stream of bytes in sequence  Use it polymorphically  Add functionality, depending on your data  This new functionality is called a “wrapper”  Just add a new and better interface to the old one, getting/sending the result from/to the same place, i.e. InputStream, resp. OutputStream  Subclassing provides the new interface

22 Example Filter is a wrapper Filter is a wrapper Builds on InputStream Builds on InputStream First obtain the sequence of bytes from the InputStream and then do the filtering First obtain the sequence of bytes from the InputStream and then do the filtering Use composition on the InputStream Use composition on the InputStream class FilterInputStream extends InputStream... protected InputStream in; FilterInputStream(InputStream in){ this.in = in;}...}

23 Comments You really have one object, many interfaces You really have one object, many interfaces Thus you avoid an explosion of the inheritance hierarchy Thus you avoid an explosion of the inheritance hierarchy  FilterInputStream is really just an InputStream with added functionality  If you wanted a DataInputStream, just wrap the InputStream in a DataInputStream object  Construct a new DataInputStream object, using the InputStream as input to the constructor

24 Important Note The primitive data-type operations of DataInputStream cannot be included in InputStream, because that object does not know about integer, float, etc The primitive data-type operations of DataInputStream cannot be included in InputStream, because that object does not know about integer, float, etc But you can make it understand these types by wrapping. But you can make it understand these types by wrapping. The neat thing: You can use a DataInputStream anywhere an InputStream is expected--thi is the advantage of inheritance The neat thing: You can use a DataInputStream anywhere an InputStream is expected--thi is the advantage of inheritance

25 Example If dataSource is of type InputStream: If dataSource is of type InputStream: InputStream dataSource; InputStream dataSource; Then the DataInputStream: Then the DataInputStream: DataInputStream typedDataSource = DataInputStream typedDataSource = new DataInputStream(dataSource); new DataInputStream(dataSource); Gets the data from exactly the same place as data retrieved from dataSource Gets the data from exactly the same place as data retrieved from dataSource We have merely provided a better interface to the same input stream We have merely provided a better interface to the same input stream

26 Another Example: Buffered Readers Use Reader s and Writer s for character data Use Reader s and Writer s for character data Start with primitive readers that directly manipulate the input data: Start with primitive readers that directly manipulate the input data:  CharArrayReader, StringReader, FileReader Now add functionality to data generated by the above Readers: Now add functionality to data generated by the above Readers:  BufferedReader, FilterReader, LineNumberReader Reader has the subclasses Reader has the subclasses  BufferedReader  FileReader  PipedReader

27 One Way to Buffer the Char Input Do it from FileReader: Do it from FileReader: BufferedReader in =new BufferedReader( new FileReader(“stuff.in”); Buffers the char file “stuff.in” Buffers the char file “stuff.in”

28 Another Way Start with Reader (which is also primitive for 16 Bit Unicodes) Start with Reader (which is also primitive for 16 Bit Unicodes) Buffer on top of it Buffer on top of it  Allow two types of buffer--a standard one with 8192 bytes and another of user-specified size  Use Reader’s capabilities and then add the buffering in the constructor

29 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);}

30 Remarks BufferedReader has methods read() and readLine() to read a single character, resp. a line of text. BufferedReader has methods read() and readLine() to read a single character, resp. a line of text. Both of these throw an IOException Both of these throw an IOException Remember to import from java.io Remember to import from java.io


Download ppt "Lecture 14 Inheritance vs Composition. Inheritance vs Interface Use inheritance when two objects share a structure or code relation Use inheritance when."

Similar presentations


Ads by Google