views:

1119

answers:

6

I'm currently doing a full rewrite of an old library, and I'm not sure how to handle this situation (for the sake of being understood, all hail the bike analogy):

I have the following classes:

TBike - the bike itself
TBikeWheel - one of the bike's wheel
TBikeWheelFront and TBikeWheelBack, both inherits from TBikeWheel and then implements the specific stuff they need on top of it

This is pretty straightforward, but now I decide to create multiple kind of bikes, each bikes having it's own kinds of wheel - they do the same stuff as a regular front/back wheels, plus the specific for that bike.

TBikeXYZ - inherits from TBike
TBikeWheelXYZ - inherits from TBikeWheel
And here is my problem: TBikeWheelFrontXYZ should inherit from TBikeWheelXYZ (to get the specific methods of an XYZ wheel), but it should also inherit from TBikeWheelFront (to get the specific methods of a front wheel).

My question here is, how can I implement that in a way that doesn't
1 - feel like a hack
2 - force me to rewrite the same code several time

Thanks

+3  A: 

Basically - you CAN'T. Delphi does not support multiple inheritance.

So left with that dilemma, the question is: could you possibly refactor that library in such a way that you can get away with using interface? Is the multiple inheritance mostly about functions and methods? If so - use interfaces. Delphi can support multiple interfaces on a class.

If the multi-inheritance is more about inheriting actual functionality in the classes, then you're probably looking at a bigger scale refactoring, I'm afraid. You'll need to find a way to break up those functional dependencies in such a way you can make it inherit from a single base class, possibly with some additional interfaces thrown in.

Sorry I can't provide an easy answer - that's just the reality of it.

Marc

marc_s
+10  A: 

Delphi does not support Multiple Inheritance. But classes can support / implement multiple interfaces and you can delegate interface implementation, so you can kinda simulate multiple inheritence.

Tim Jarvis
+2  A: 

You can try to extract an interface, say IFrontWheel, out of TBikeWheelFront, so that it is a subclass of TBikeWheel but implements IFrontWheel. Then TBikeWheelXYZ inherits from TBikeWheel and TBikeWheelFrontXYZ inherits from TBikeWheelXYZ and implements IFrontWheel.

Then you can define a class TFrontwheel and give it the same methods as the interface, but now you implement them. Then TBikeWheelFront and TBikeWheelXYZ get a private member of type TFrontwheel and the IFrontWheel implementations of them simply delegate to the private member methods.

This way you don't have double implementations.

Ozan
+7  A: 

Use interfaces. Something like this (Off the top of my head, based on your description.....)

type

  IBikeWheel = interface
    ...
  end;

  IXYZ = interface
    ...
  end;

  IFrontWheel = interface(IBikeWheel)
    ...
  end;


  TBike = class
    ...
  end;

  TBikeWheel = class(TObject, IBikeWheel);

  TBikeWheelXYZ = class(TBikeWheel, IXYZ);

  TBikeFrontWheelXYZ = class(TBikeWheelXYZ, IFrontWheel);

Then implement classes for the interfaces that do what the corresponding classes in your old (presumably C/C++) library does and instantiate them in the corresponding class's constructor.

Nick Hodges
+2  A: 

Use polymorhism to implment each 'thing' as an object hierarchy in its own right and then add object properties to that object in turn. So, create a hierarchy of wheels, and a hierarchy of bikes. Then add wheels to bikes as fields in the ancestor bike object. See below.

  TBikeWheel = class
  TBikeWheelXYZ = class( TBikeWheel ) 

  TBike = class
    FFrontWheel : TBikeWheel;
    property FrontWheel : TBikeWheel
      read FrontWhell  

  TBikeABC = class( TBike)
    constructor Create;
  end;

  constructor TBikeABC.Create;
  begin
    inherited;
    FFrontWheel := TBikeWheel.Create;
  end;

  TBikeXYZ = class( TBike)
    constructor Create;
  end;

  constructor TBikeXYZ.Create;
  begin
    inherited;
    FFrontWheel := TBikeWheelXYZ.Create;
  end;
Brian Frost
+1, containment often models reality much better than inheritance.
mghie
A: 

A variation of Brian Frost's suggestion:

  TBikeWheel = class
  TBikeWheelXYZ = class( TBikeWheel ) 

  TBike = class
    FFrontWheel : TBikeWheel;
  protected
    function CreateWheel: TBikeWheel; virtual;
  public
    property FrontWheel : TBikeWheel
      read FrontWheel  
  end;

  TBikeABC = class( TBike)
  protected
    function CreateWheel: TBikeWheel; override;
  end;

  function TBikeABC.CreateWheel: TBikeWheel;
  begin
    result := TBikeWheel.Create;
  end;

  TBikeXYZ = class( TBike)
  protected
    function CreateWheel: TBikeWheel; override;
  end;

  function TBikeXYZ.CreateWheel: TBikeWheel;
  begin
    result := TBikeWheelXYZ.Create;
  end;
Uwe Raabe