How to layout class definition when inheriting from multiple interfaces

Posted by gabr on Programmers See other posts from Programmers or by gabr
Published on 2011-11-22T07:49:43Z Indexed on 2011/11/22 10:24 UTC
Read the original article Hit count: 227

Given two interface definitions ...

IOmniWorkItem = interface ['{3CE2762F-B7A3-4490-BF22-2109C042EAD1}']
  function  GetData: TOmniValue;
  function  GetResult: TOmniValue;
  function  GetUniqueID: int64;
  procedure SetResult(const value: TOmniValue);
//
  procedure Cancel;
  function  DetachException: Exception;
  function  FatalException: Exception;
  function  IsCanceled: boolean;
  function  IsExceptional: boolean;
  property Data: TOmniValue read GetData;
  property Result: TOmniValue read GetResult write SetResult;
  property UniqueID: int64 read GetUniqueID;
end;

IOmniWorkItemEx = interface ['{3B48D012-CF1C-4B47-A4A0-3072A9067A3E}']
  function  GetOnWorkItemDone: TOmniWorkItemDoneDelegate;
  function  GetOnWorkItemDone_Asy: TOmniWorkItemDoneDelegate;
  procedure SetOnWorkItemDone(const Value: TOmniWorkItemDoneDelegate);
  procedure SetOnWorkItemDone_Asy(const Value: TOmniWorkItemDoneDelegate);
//
  property OnWorkItemDone: TOmniWorkItemDoneDelegate read GetOnWorkItemDone write SetOnWorkItemDone;
  property OnWorkItemDone_Asy: TOmniWorkItemDoneDelegate read GetOnWorkItemDone_Asy write SetOnWorkItemDone_Asy;
end;

... what are your ideas of laying out class declaration that inherits from both of them?

My current idea (but I don't know if I'm happy with it):

TOmniWorkItem = class(TInterfacedObject, IOmniWorkItem, IOmniWorkItemEx)
strict private
  FData              : TOmniValue;
  FOnWorkItemDone    : TOmniWorkItemDoneDelegate;
  FOnWorkItemDone_Asy: TOmniWorkItemDoneDelegate;
  FResult            : TOmniValue;
  FUniqueID          : int64;
strict protected
  procedure FreeException;
protected //IOmniWorkItem
  function  GetData: TOmniValue;
  function  GetResult: TOmniValue;
  function  GetUniqueID: int64;
  procedure SetResult(const value: TOmniValue);
protected //IOmniWorkItemEx
  function  GetOnWorkItemDone: TOmniWorkItemDoneDelegate;
  function  GetOnWorkItemDone_Asy: TOmniWorkItemDoneDelegate;
  procedure SetOnWorkItemDone(const Value: TOmniWorkItemDoneDelegate);
  procedure SetOnWorkItemDone_Asy(const Value: TOmniWorkItemDoneDelegate);
public
  constructor Create(const data: TOmniValue; uniqueID: int64);
  destructor Destroy; override;
public //IOmniWorkItem
  procedure Cancel;
  function  DetachException: Exception;
  function  FatalException: Exception;
  function  IsCanceled: boolean;
  function  IsExceptional: boolean;
  property Data: TOmniValue read GetData;
  property Result: TOmniValue read GetResult write SetResult;
  property UniqueID: int64 read GetUniqueID;
public  //IOmniWorkItemEx
  property OnWorkItemDone: TOmniWorkItemDoneDelegate read GetOnWorkItemDone write SetOnWorkItemDone;
  property OnWorkItemDone_Asy: TOmniWorkItemDoneDelegate read GetOnWorkItemDone_Asy write SetOnWorkItemDone_Asy;
end;

As noted in answers, composition is a good approach for this example but I'm not sure it applies in all cases. Sometimes I'm using multiple inheritance just to split read and write access to some property into public (typically read-only) and private (typically write-only) part. Does composition still apply here? I'm not really sure as I would have to move the property in question out from the main class and I'm not sure that's the correct way to do it.

Example:

// public part of the interface interface
IOmniWorkItemConfig = interface
  function  OnExecute(const aTask: TOmniBackgroundWorkerDelegate): IOmniWorkItemConfig;
  function  OnRequestDone(const aTask: TOmniWorkItemDoneDelegate): IOmniWorkItemConfig;
  function  OnRequestDone_Asy(const aTask: TOmniWorkItemDoneDelegate): IOmniWorkItemConfig;
end;

// private part of the interface
IOmniWorkItemConfigEx = interface ['{42CEC5CB-404F-4868-AE81-6A13AD7E3C6B}']
  function  GetOnExecute: TOmniBackgroundWorkerDelegate;
  function  GetOnRequestDone: TOmniWorkItemDoneDelegate;
  function  GetOnRequestDone_Asy: TOmniWorkItemDoneDelegate;
end;

// implementing class
TOmniWorkItemConfig = class(TInterfacedObject, IOmniWorkItemConfig, IOmniWorkItemConfigEx)
strict private
  FOnExecute        : TOmniBackgroundWorkerDelegate;
  FOnRequestDone    : TOmniWorkItemDoneDelegate;
  FOnRequestDone_Asy: TOmniWorkItemDoneDelegate;
public
  constructor Create(defaults: IOmniWorkItemConfig = nil);
public //IOmniWorkItemConfig
  function  OnExecute(const aTask: TOmniBackgroundWorkerDelegate): IOmniWorkItemConfig;
  function  OnRequestDone(const aTask: TOmniWorkItemDoneDelegate): IOmniWorkItemConfig;
  function  OnRequestDone_Asy(const aTask: TOmniWorkItemDoneDelegate): IOmniWorkItemConfig;
public //IOmniWorkItemConfigEx
  function  GetOnExecute: TOmniBackgroundWorkerDelegate;
  function  GetOnRequestDone: TOmniWorkItemDoneDelegate;
  function  GetOnRequestDone_Asy: TOmniWorkItemDoneDelegate;
end;

© Programmers or respective owner

Related posts about coding-style

Related posts about delphi