1. Home
  2. Computing & Technology
  3. Delphi Programming

Using and Abusing Inheritance - Delphi OOP Part 7 - Chapter 16

By Zarko Gajic, About.com Guide

The problem of roles

Another problem arises when subclasses are used to model roles instead of subclasses. This can be quite subtle. For example, the hierarchy as shown below, where Table and Chair are subclasses of Furniture, seems quite acceptable.
type
   TFurniture = class;

   TChair = class(TFurniture) ;

   TTable = class(TFurniture) ;
By comparison, are Monthly paid and Weekly paid employees subclasses of Employee?
type
   TEmployee = class;

   TMonthly = class(TEmployee) ;

   TWeekly = class(TEmployee) ;
Although the two "code" blocks seem so similar, there is a subtle difference between them, and that is the lifetime of a role. Once a chair is always a chair – the chair won’t suddenly be changed into a table.

However, it is quite possible that the employee who currently has the role of weekly paid employee may be appointed to a different role, and so become a monthly paid employee. If this happens in a system with the structure shown, it becomes necessary to create a new monthly paid employee object, to copy all the relevant data from the weekly paid employee object, and then to destroy the weekly paid object. This is a lot of work with considerable potential for error.

Anti-Pattern 7.3 Subclassing a role

When an object takes on different roles or functions under different circumstances, it is clumsy to model these various roles as subclasses, since a change in role will then necessitate the creation of a new object for the new role, copying the state of the old role to the new role, and then deleting the object modelling the old role.

Where a set of properties and behaviour are an inherent, unchanging characteristic they typically constitute a subclass. Where the properties and behaviour change over time, they constitute a role.

Therefore, instead of subclassing a role, separate the roles into a different hierarchy that uses interface inheritance. Make the root of this separate hierarchy an attribute of the original superclass.
By substitution, the value of this attribute can be set to any of the subtypes. Thus a role change is accommodated by changing the attribute to refer to a different subtype rather than through a create, copy, delete cycle.

Convenience versus semantics

If one’s only focus in adopting OO is to re-use as much existing code as possible, it is tempting to re-use whatever functionality is already present wherever we can find it. Unfortunately this can lead to inheritance hierarchies that are quite complex and do not necessarily reflect accurately the situation they are modelling.

Anti-Pattern 7.4 Construction convenience

For the sake of convenience in construction, it is tempting to derive a new class from an existing class even when there is only a limited conceptual relationship between the two classes. However, because there is not a valid IsA relationship between the two classes, this can lead to a variety of problems (as indicated above) because of the tight coupling that is introduced when one class is derived from another.

Therefore, where a valid IsA relationship does not exist between two classes, do not derive one from the other. Instead, depending on the strength of the relationship, consider various forms of restructuring as suggested in the previous anti-patterns. If the relationship is very slight, it may be necessary to recode the apparently related functionality again in the new class rather than introduce a high level of coupling by inappropriately deriving one from the other (whether through inheritance or through composition).

The reduced coupling means that the two classes can in the future change independently of each other, so facilitating future evolution of the system.

Requirements / Tests for implementation inheritance

The theme of this chapter so far has been: Just because a programming language offers implementation inheritance does not mean that it should be used at every opportunity!

Implementation inheritance introduces very tight coupling between the superclass and the subclass and so should only be used where a subclass is also a valid subtype.

So how does one decide when to use implementation inheritance and when not? The basic test for implementation inheritance is the IsA test. Is the proposed subclass a superclass in all respects? Do all features of the superclass apply to the subclass, possibly with some extensions but with minimal need for overriding? Although one cannot know for sure, it is also worth considering whether future changes to the superclass will be beneficial and/or not detrimental to the subclass.

A second test is the role test. If the proposed subclass is actually a role of the superclass, it should not be derived from the superclass.

Explore Delphi Programming
About.com Special Features

Stay connected and entertained with reviews on tips on the latest HDTVs, cellphones and more. More >

Easy ways to connect two computers for networking purposes. More >

  1. Home
  2. Computing & Technology
  3. Delphi Programming
  4. Coding Delphi Applications
  5. OOP in Delphi
  6. Free Online OOP Course
  7. Using and Abusing Inheritance - Delphi OOP Part 7 - Chapter 16

©2009 About.com, a part of The New York Times Company.

All rights reserved.