34
Copyright@2014 Taylor & Francis Adair Dingle All Rights Reserved ObjectOriented Design Inheritance vs. Delega@on Inheritance for Polymorphism: Behavioral Reuse

Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Embed Size (px)

Citation preview

Page 1: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Object-­‐Oriented  Design    

Inheritance    vs.    

Delega@on      

   Inheritance for Polymorphism: Behavioral Reuse

Page 2: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Design  Ques@ons  

•  How  to  streamline  class  design  for  dynamic  behavior?  

•  What  is  the  importance  of  an  interface?      

•  How  to  dis@nguish  between  reuse  mo@ves?  

Copyright@2015                Adair  Dingle  

Page 3: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Key  Observa@ons  

•  Inheritance  and  delega@on  BOTH  may  provide  polymorphism  

•  Type  dependencies  may  be  external  or  internal    

•  Differing  needs  for  control  may  drive  design  

Copyright@2015                Adair  Dingle  

Page 4: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Chapter  7:  Behavioral  Design    Invoca@on  of  Func@onality      run-­‐&me  variability  vs.  compile-­‐&me  efficiency  

 •  Polymorphism  •  Sta@c  vs.  Dynamic  Binding  •  Languages  Difference  •  Design  Principles      

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 5: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Three  Forms  of  Polymorphism    •  Overloading    aka    Ad  Hoc  Polymorphism  

–  Allows  mul@ple  func@on  defini@ons  with  same  name  –  compiler  uses  parameter  type(s)  to  resolve  func@on  calls  

•  Generics    aka    Parametric  Polymorphism  –  Supports  ‘typeless’  defini@on  of  a  class  or  a  func@on  –  applica@on  programmer  can  later  supply  type  –  Compiler  generates  version  of  generic  class  (or  func@on)  with  that  

type.    

•  SubTyping    aka    Inclusion  –  describes  design  of  class  hierarchy  where  descendant  classes  

(re)define,  augment,  or  modify  inherited  func@onality  –  Descendant  classes  are  dependent  on  the  base  class  interface  –  Dynamic  binding  expected    

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 6: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.1    Overloaded  Func@ons:  Moderately  Altered  Func@onality    

void reset() { for (int k=0; k < size; k++)

A[k] = 0.0;

}

void reset(double value) { for (int k=0; k < size; k++)

A[k] = value;

}

void reset(bool op, int factor) { if (op)

for (int k=0; k < size; k++) A[k]*= factor;

else

for (int k=0; k < size; k++) A[k] += factor;

}

   

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 7: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.2    Overloaded  Func@ons:  Consistent  Behavior  =>  Generic  Func@on  

void swap(int& x, int& y) { int hold = x;

x = y; y = hold;

}

void swap(float& x, float& y) { float hold = x;

x = y; y = hold;

}

template <typename someType> void swap(someType& x, someType& y) { someType hold = x;

x = y; y = hold;

}    

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 8: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Third  Form  of  Polymorphism    •  Overloading      

–  Allows  mul@ple  func@on  defini@ons  with  same  name  

•  Generics        –  ‘typeless’  defini@on  of  a  class  or  a  func@on    

•  SubTyping  depends  on  dynamic  binding  –  Associate  func@on  call  resolu@on  with  subtype  –  POSTPONE  func@on  call  resolu@on  un@l  run-­‐@me  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 9: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Sta@c  vs.  Dynamic  Binding  

•  Sta@c  binding    –  compiler  resolves  func@on  calls  –  translates  each  func@on  invoca@on  into  a  direct  jump    –  efficient  but  rigid  

•  Dynamic  binding    –  compiler  does  not  resolve  a  func@on  call  at  compile-­‐@me.      –  extra  instruc@ons  generated    –  at  run-­‐@me,  func@on  address  extracted  from  a  jump  table  –  flexible  but  costly  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 10: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Sta@c  vs.  Dynamic  Binding  

Sta@c  binding  translates  func@on  calls  directly  into  jump  statements  

⇒ func@on  invoked  at  the  point  of  call  CANNOT  vary  ⇒ No  run-­‐@me  overhead  ⇒ No  run-­‐@me  flexibility    

Dynamic  binding  postpones  func@on  call  resolu@on  un@l  run-­‐@me    

⇒ func@on  invoked  at  the  point  of  call  CAN  vary  ⇒ great  flexibility  ⇒ Run-­‐@me  overhead  ⇒ supports  polymorphism  and  heterogeneous  collec@ons      

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 11: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Binding  Design  Choices  

•  Java  –  NONE:    All  func@ons  dynamically  bound  (EXPENSIVE!)  

•  C#/C++  –  Sta@c  binding  by  default  (efficient!)  –  Dynamic  binding  with  keyword  ‘virtual’  

•  Sta@c  binding  –  Reasonable  when  func@on  choice  will  not  vary  

•  Dynamic  binding  –  Reasonable  when  subtype  affects  func@on  choice  –  Heterogeneous  collec@ons  needed  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 12: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Once  Virtual  Always  Virtual  

•  See  sec@on  7.4  •  Address  of  each  virtual  func@on  placed  in  class  vtab    

–  “vtab”  =  =  virtual  func@on  table  =  =  jump  table      

•  Descendant  class  inherits  copy  of  parent’s  vtab  –  Every  virtual  func@on  remains  virtual  for  all  descendants  –  Each  virtual  func@on  with  the  same  name  has  the  same  offset  in  each  class  vtab  

=>  Name  corresponds  to  offset  with  class  hierarchy      

•  Each  overridden  func@on    –  causes  an  address  update  in  corresponding  entry  of  vtab  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 13: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Heterogeneous  Collec@on  

•  Tied  to  interface  of  base  class  in  class  hierarchy  –  Available  func@onality  defined  by  public  func@ons  of  base  class  

•  Contains  assortment  of  objects  –  Each  object  some  (sub)type  of  class  hierarchy  –  No  required  order  or  frequency  of  (sub)types  

•  Elements  of  collec@on  are  actually  address  holders  –  References  in  C#  –  Pointer  in  C++  

•  Dynamic  binding  –  Postpones  func@on  resolu@on  un@l  run-­‐@me  so  actual  subtype  used  –  Great  flexibility  and  extensibility!!  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 14: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Heterogeneous  Collec@on  

•  Class  hierarchy  uses  virtual  func@ons    –  variant  behavior  (based  on  subtype)  

 •  Traversal  of  heterogeneous  collec@on    

–  Yields  streamline  execu@on  of  varying  func@onality  –   Masks  subtype  construc@on  and  evalua@on      

•  Type  extensibility  supported    

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 15: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Table  7.1    Types  of  Polymorphism  

Polymorpism Characteristics Distinguished by Application

Ad Hoc (Overloading)

Different function versions

Function signature (parameter lists)

Constructors often overloaded

Parametric (Generic)

Type-less functions Type placeholder Multiple (typed) versions automatically generated by compiler

Inclusion (Subtype)

Overridden functions

Same function signature Class scope differs

Heterogeneous collections base class interface Dynamic binding

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 16: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.8    C++  Polymorphic  Object  Crea@on  

// function that evaluates environment, possibly file input

// generates an object of some type from class hierarchy

// => can return address of any object from class hierarchy

// => subtype of object allocated determined at run-time

// BASE pointer can hold address of ANY class hierarchy object // at compile-time:

// return pointer holding address generated at run-time

// cannot ‘guess’ what (sub)type of object allocated

FirstGen* GetObjAddr() { if (condA) return new FirstGen; // base

else if (condB) return new SecondGen; // derived

else if (condC) return new ThirdGen; // derivedII

} // ownership of object passed back

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 17: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.9    C#  Polymorphic  Object  Crea@on  

// function that evaluates environment, possibly file input

// generates an object of some type from class hierarchy

// => can return address of any object from class hierarchy

// => subtype of object allocated determined at run-time

// BASE reference can hold address of ANY class hierarchy object // at compile-time:

// return reference (address of object generated at run-time)

// cannot ‘guess’ what (sub)type of object allocated

FirstGen GetObj() { if (condA) return new FirstGen(); // base

else if (condB) return new SecondGen(); // derived

else if (condC) return new ThirdGen(); // derivedII

} // ownership of object passed back

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 18: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.10    C++  Heterogeneous  Collec@on  

// initialization of heterogeneous collection:subtype hidden // at compile-time, do NOT know type of object generated

FirstGen* bigPtrArray[100];

for (int k = 0; k < 100; k++)

bigPtrArray[k] = GetObjAddr();

// dynamic behavior for (int k = 0; k < 100; k++)

bigPtrArray[k]-> simple();

// MEMORY MANAGEMENT: release heap memory before leaving scope // deallocate dynamically allocated objects

for (int k = 0; k < 100; k++)

delete bigPtrArray[k];

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 19: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.11    C#  Heterogeneous  Collec@on  

// initialization of heterogeneous collection:subtype hidden // at compile-time, do NOT know type of object generated

FirstGen[] bigArray = new FirstGen[100];

for (int k = 0; k < bigArray.Length; k++)

bigArray[k] = GetObj(); // dynamic behavior for (int k = 0; k < bigArray.Length; k++)

bigArray[k]-> simple();

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 20: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Abstract  Classes  

•  An  abstract  class  is  an  ‘incomplete’  type  defini@on  •  Objects  cannot  be  instan@ated  from  abstract  class  

–  at  least  one  method  remains  undefined  OR  –  no  public  constructors  provided  

•  Abstract  classes    –  define  a  common  interface  for  a  class  hierarchy  –  Typically  define  virtual  func@ons  in  interface  

=>  Design  interface  of  heterogeneous  collec@on  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 21: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Table  7.3    Abstract  Classes  Design Intent Implementation Details Effects

Incomplete Type Definition Deferred methods

Not all functions defined Function prototypes serve as placeholders

Cannot instantiate objects Inheritance required

Base class defines uniform interface for class hierarchy

Derived class(es) override or augment behavior

Inheritance anticipated

Polymorphism: Calls through base typed pointer (reference) resolved wrt base interface

Typed pointer or reference holds address of derived object

Heterogeneous collections Varying behavior Extensibility

Generalization of overriding

Derived class(es) define behavior

Derived class remains abstract unless it redefines inherited deferred methods

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 22: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.12    C++  Abstract  Class  

class Shape // abstract class: pure virtual methods { public:

virtual void rotate(int) = 0; virtual void draw() = 0; …

};

// inherited methods defined => descendant class not abstract class Circle: public Shape

{ point center; int radius;

public:

Circle(point p, int r):center(p), radius(r) {}

// once virtual, always virtual void rotate(int){}

// for readability tag as virtual virtual void draw();

};

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 23: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.13    Cannot  Instan@ate  Abstract  Class  

Shape s; // cannot instantiate from abstract class Shape* sptr; // can hold address of derived objects

// abstract Shape and derived subtypes Circle, Square, …

// initialize array of Shape pointers

// each pointer can contain address of different subtype

// input function GetObject() constructs some Shape subtype

// on heap and return its address

int main()

{ Shape* composite[100];

for (int i=0; i<100; i++)

composite[i] = GetObjectAddr();

// what is drawn?

for (int i=0; i<100; i++)

composite[i]->draw();

}

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 24: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.14    C#  Abstract  Class  

// abstract easily noted with keyword

abstract class Shape

{ public virtual void rotate(int); public virtual void draw(); …

}

// see section 7.6 for real-world example

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 25: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Tracking    (sub)Type  

•  Compiler  effec@vely  tracks  type  •  Modern  OO  constructs  increase  abstrac@on  

–  inheritance    –  virtual  func@ons    

•  Applica@on  programmer  need  not  track  (sub)type  –  NO  ‘manual’  type  checking  

•  Type  checking  in  code  (‘manual’)  –  tedious  and  error-­‐prone  –  poten@ally  expensive  –  non-­‐extensible  approach.    

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 26: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.18  Type  Extrac@on  in  C++  

class Base { public:

virtual void surprise();

// process() NOT virtual => statically bound call // => even if overridden, always yields Base functionality void process();

};

// APPLICATION CODE: heterogeneous collections

// virtual function surprise() == automatic type checking

// non-virtual function process() == no type checking // => manual type-checking if Derived behavior desired // when function is not virtual in the Base class

Copyright@2014                Taylor  &  Francis              

Adair  Dingle      All  Rights  Reserved  

Page 27: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.18  Type  Extrac@on  con@nued  

// process() non-virtual => forced type checking: dynamic_cast // run-time type check of object whose address held in pointer

// pointer value returned if type matches

// zero if cast fails

for (int i=0; i<100; i++)

{ // elegant: compiler sets up dynamic invocation HeteroDB[i]->surprise();

// clunky, tedious, not extensible if (Child1* ptr = dynamic_cast<Child1*> (HeteroDB[i]))

ptr->process();

else if (Child2* ptr = dynamic_cast<Child2*> (HeteroDB[i]))

ptr->process();

else if (Child3* ptr = dynamic_cast<Child3*> (HeteroDB[i]))

ptr->process();

… // for all relevant subtype variants, test cast else … // catchall: process unmatched subtype

}

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 28: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.19  Type  Extrac@on  in  C#  // same setup: Base class with virtual surprise() & non-virtual process() for (int i=0; i<100; i++)

{ // elegant: compiler sets up dynamic invocation

HeteroDB[i].surprise();

// clunky, tedious, not extensible if (HeteroDB[i] is Child1)

{ Child1 x = HeteroDB[i] as Child1);

x.process();

}

else if (HeteroDB[i] is Child2)

{ Child2 x = HeteroDB[i] as Child2);

x.process();

}

else if (HeteroDB[i] is Child3)

{ Child3 x = HeteroDB[i] as Child3);

x.process();

}

… // for all relevant subtype variants, test cast else … // catchall: process unmatched subtype

}

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 29: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Example  7.20  Type  Reclama@on  in  C++  

// virtual whoami() in class hierarchy yields identifying int // myObj is base class pointer, just like HeteroDB[i]

int typeId myObj->whoami(); switch typeId: { case 0: SubType0 ptr = static_cast<SubType0*> (myObj);

ptr->process();

break;

case 1: SubType1 ptr = static_cast<SubType1*> (myObj);

ptr->process();

break;

case 8: SubType8 ptr = static_cast<SubType8*> (myObj);

ptr->process();

}

Copyright@2014                Taylor  &  Francis              

Adair  Dingle      All  Rights  Reserved  

Page 30: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Type  Extensibility  

•  Design  of  an  inheritance  hierarchy  may  be  expanded    •  Addi@onal  descendant  classes  easily  defined  •  What’s  needed?  

–  an  appropriately  designed  base  class  interface  –  proper  use  of  polymorphism    

⇒ new  descendant  classes  added  without  breaking  client  code  

⇒ Sotware  maintainability  (evolu@on  supported)  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 31: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Polymorphism  and  Maintainability    

•  Overloading    aka    Ad  Hoc  Polymorphism  –  should  make  code  more  readable  –  can  isolate  func@onal  varia@ons  based  on  parameter  type  

•  Generics    aka    Parametric  Polymorphism  –  promotes  code  reuse  and  familiarity  –  standard  classes  and  func@ons  

•  SubTyping  aka    Inclusion  –  supports  type  extensibility  –  applica@on  code  does  not  break  when  new  subtype  added  to  class  hierarchy.    

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 32: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Table  7.10  Func@on  Name  Reuse  Overloaded Overridden Virtual

Same name Number, order, type of parameters varies

Same name Same signature Same class hierarchy

Same name Same signature Same class hierarchy

Function signature Parameters drive selection

May or may not be dynamically bound (C#,C++)

Dynamic Binding function call resolved at run-time

Offers choice based on parameters

Redefines inherited functionality

May be overridden in derived class(es)

Constructors often overloaded

Return type not part of signature

Requires vtab Type of this pointer not known until run-time

Distinct functions Masks parent method Overhead of indirect call

Overloaded for variety May NOP inherited method

Prevents inlining functions

Overloaded for type ð  generics

Extensible

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 33: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Open  Closed  Principle  A  class  should  be  open  for  extension  and  closed  for  modifica&on    •  Emphasis  on  Sotware  maintainability  •  Polymorphism:  Common  Interface  in  Base  Class  

–  base  type  defines  key  func@onality    –  defers  complete  implementa@on  to  descendant  classes,  OR  –  variant  behavior  among  within  a  heterogeneous  collec@on  

•  As  sotware  evolves  –  base  class  should  be  stable  (closed  to  modifica@on)  –  design  of  addi@onal  descendants  expected  (open  for  extension).    

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved  

Page 34: Object-oriented Design: Polymorphism via Inheritance (vs. Delegation)

Liskov  Subs@tu@on  Principle  

Given  a  type  T  with  a  subtype  S  defined  via  inheritance,  any  object  of  subtype  S  can  serve  in  place  of  an  object  of  type  T      

•  Strong  support  of  is-­‐a  rela@onship  •  Any  descendant  can  stand  in  for  parent  object  •  Implies  the  power  of  heterogeneous  collec@ons  

•  Great  variability  achievable  in  stable  sotware  systems    •  Type  extensibility  and  sotware  maintainability  

Copyright@2014                Taylor  &  Francis              Adair  Dingle      All  Rights  Reserved