In Delphi, the reserved word “interface” has two distinct meanings. In a Delphi unit, “interface” denotes the start of a unit section used to declare public constants, data types, variables, procedures and functions visible and accessible to other units using this unit. In OOP jargon, an “object interface” or simply “interface” is a kind of a class with no implementation (but not like a class with abstract methods). An interface defines methods that can be implemented by a class (a class “implements” the interface). Object interfaces might be used when multiple inheritance is needed, and are frequently used when working with COM objects. For some intro to interfaces: Interfaces in Delphi Programming 101.
In recent days I’ve been playing with some COM objects (developed in C++, consuming in my Delphi application) exposing properties (and methods) of interface type.
In some pseudo code, that would look like:
anObject : ISomeObject; //has a property IProperty of IInterfaceProperty type objProperty : IInterfaceProperty ... objProperty := anObject.IProperty objProperty.DoSomething; //or anObject.IProperty.DoSomething;
Some properties are declared as read/write – allowing the consumer (me) of the object to reimplement that property’s implementation. Since the property IProperty has a setter and is of IInterfaceProperty type – reimplementing what it does is rather simple: create a Delphi class implementing IInterfaceProperty and set it for the IProperty of the object. When creating my reimplementing class, store the reference to the original IProperty implementation and when there’s no need to override a particular method – just call the original method in my “overridden” method. Case closed 🙂
The “problem” I encountered is: IInterfaceProperty has tons of methods and my custom IInterfaceProperty implementing class must implement all of them (even if I would just call the original method implementation) – while I need to override only a few. Hence the idea for this post:
How to Partially Override Interface Implementation
Ok, let’s try to create a simple setup as above. Hint: noting with interfaces is simple.
The IInterfaceProperty will be IMyInterface and defines a bunch of functions, for the sake of simplicity, something like:
type IMyInterface = interface(IInterface) function F1 : integer; function F2 : integer; //and many more... //function F3 : integer; //function F4 : integer; //function F5 : integer; //.. //function FN : integer; end;
And then we have a class implementing that interface and exposing the interface implementation via a read/write property:
TMyClass = class(TInterfacedObject, IMyInterface) strict private type TMyInterfaceImpl = class(TInterfacedObject, IMyInterface) function F1 : integer; function F2 : integer; end; private fMyInterface: IMyInterface; public property MyInterface : IMyInterface read fMyInterface write fMyInterface implements IMyInterface; function MinusF1 : integer; constructor Create(); end;
Here’s the implementation part:
constructor TMyClass.Create; begin inherited; fMyInterface := TMyInterfaceImpl.Create; end; function TMyClass.MinusF1: integer; begin result := -1 * self.MyInterface.F1; end;
So, when the object of TMyClass is created the constructor assigns to fMyInterface an instance of a class actually internally implementing the interface methods:
function TMyClass.TMyInterfaceImpl.F1: integer; begin result := 1; end; function TMyClass.TMyInterfaceImpl.F2: integer; begin result := 2; end;
If you look inside Delphi help, that’s called “implementing interfaces by delegation – delegating to an interface-type property”.
Ok, so far all set. Here’s a simple test to prove this all works:
var my : TMyClass; begin my := TMyClass.Create; Writeln ('F1: ' + my.MyInterface.F1.ToString); Writeln ('F2: ' + my.MyInterface.F2.ToString); Writeln ('-F1: ' + my.MinusF1.ToString); end;
The output would be:
Note how MinusF1 function depends on the implementation of F1 – by changing (/”overriding”) the implementation of F1 I would be implicitly changing the inner workings of TMyClass.
Now, what I want is to reimplement what my.MyInterface methods do. As stated above, the direct approach is to create a class implementing IMyInterface and assign it to my.MyInterface, like in:
TMyPlus100Class = class(TInterfacedObject, IMyInterface) private fIOriginal: IMyInterface; public constructor Create(const original : IMyInterface); //must implement all IMyInterface methods function F1: integer; function F2: integer; //… // function FN: integer; end;
The implementation for each Fx function is whatever we need:
constructor TMyPlus100Class.Create(const original : IMyInterface); begin self.fIOriginal := original; end; function TMyPlus100Class.F1: integer; begin //add 100 to original result – so like override method implementation result := 100 + fIOriginal.F1; end; function TMyPlus100Class.F2: integer; begin //just return original value result := fIOriginal.F2; end;
To use my reimplementing class I would do:
my := TMyClass.Create; my.MyInterface := TMyPlus100Class.Create(my); Writeln ('Plus100 F1:' + my.MyInterface.F1.ToString); Writeln ('Plus100 F2:' + my.MyInterface.F2.ToString); Writeln ('Plus100 -F1: ' + my.MinusF1.ToString);
And the output would be
Plus100 -F1: -101
Now, that’s all great and works as expected. However, I need to override just a few methods. My TMyPlus100Class must implement all functions F1 … FN while mostly all I will do is to return the original value and only for some methods I would return something else.
So, the idea is to have a reimplementing class store the original implementation as a property by delegation and try to “override” just one method (say “F1″):
TMyPlus200Class = class(TInterfacedObject, IMyInterface) private fIOriginal: IMyInterface; property IOriginal : IMyInterface read fIOriginal implements IMyInterface; public constructor Create(const original : IMyInterface); //"override" just F1 function F1: integer; end; function TMyPlus200Class.F1: integer; begin result := 200 + fIOriginal.F1; end;
This looks ok, and compiles, but once used:
my := TMyClass.Create; my.MyInterface := TMyPlus200Class.Create(my); Writeln ('Plus200 F1:' + my.MyInterface.F1.ToString); Writeln ('Plus200 F2:' + my.MyInterface.F2.ToString); Writeln ('Plus200 -F1: ' + my.MinusF1.ToString);
The output would be
Plus200 -F1: -1
Nothing happened!! My TMyPlus200Class did nothing. That's actually to expect, as if you read the Help: If the delegate property is of a class type, that class and its ancestors are searched for methods implementing the specified interface before the enclosing class and its ancestors are searched.
If I try to use something called “method resolutions for interface”, like:
TMyPlus200Class = class(TInterfacedObject, IMyInterface) private fIOriginal: IMyInterface; property IOriginal : IMyInterface read fIOriginal implements IMyInterface; public constructor Create(const original : IMyInterface); function F1: integer; function IMyInterface.F1 = F1; //<- Please use my F1 as an override for IOriginal.F1 end;
The above does not compile with : E2264 Cannot have method resolutions for interface 'IMyInterface'.
So, what now? Well, let’s try introducing another class with a derived class and method resolution, as in:
TMyPlus300Class = class(TInterfacedObject, IMyInterface) private fIOriginal: IMyInterface; property IOriginal : IMyInterface read fIOriginal implements IMyInterface; public constructor Create(const original : IMyInterface); function _F1: integer; end; TMyPlus300ClassImplementator = class(TMyPlus300Class, IMyInterface) public function IMyInterface.F1 = _F1; end;
Note: IOriginal is a private property of TMyPlus300Class, TMyPlus300ClassImplementator extends TMyPlus300Class and uses method resolution to specify what method ("_F1") actually implements the IMyInterface's F1 method.
Also note that the name of "_F1" function can be any other name. It just cannot be "F1", so I'm prefixing it with an underscore character. The name could have been anything else, like "MyReimplementedF1".
constructor TMyPlus300Class.Create(const original: IMyInterface); begin self.fIOriginal := original; end; function TMyPlus300Class._F1: integer; begin result := 300 + self.IOriginal.F1; end;
When pushing my partial re-implementation I just need to make sure I create an instance of TMyPlus300ClassImplementator (and NOT TMyPlus300Class), as in:
my := TMyClass.Create; my.MyInterface := TMyPlus300ClassImplementator.Create(my); Writeln ('Plus300 F1:' + my.MyInterface.F1.ToString); Writeln ('Plus300 F2:' + my.MyInterface.F2.ToString); Writeln ('Plus300 -F1: ' + my.MinusF1.ToString);
And the output:
Plus300 -F1: -301
Voila! Just re-implemented the interface implementation partially: only one method returns a different result compared to original implementation.
If you are still reading: bravo. I got lost of all the interface this implementation that 😉
Disclaimer: I'm not freeing any objects above, yes I know.
wow very good post and a really nice idea!