How to layout class definition when inheriting from multiple interfaces
- by gabr
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;