2

I work with Delphi 2006 and I have a complex class named TMyClassTest that have many methods Some of those methods create nonvisual components and assign event handlers of those components and run methods of those components.

Also I have two classes that implement the same interface like below:

TMyClass1 = class(Class1, Interface1)
   ... //procedures from the Interface1
   procedure MyClass1Proc1;
 end;

TMyClass2 = class(Class2, Interface1)
   ... //procedures from the Interface1
   procedure MyClass2Proc1;
   procedure MyClass2Proc2
 end;

Now I need that TMyClass1 and TMyClass2 to 'inherit' the TMyClassTest, too. Much more ... Interface1 must contain (beyond its methods) all the methods from the MyClassTest. How can I avoid to implement (like copy/paste) on both clases (TMyClass1 and TMyClass2) all the procedures from TMyClassTest ? I don't want to keep the same code on three separate places.

Based on Arioch's comments I created a solution like: (see http://docwiki.embarcadero.com/RADStudio/XE3/en/Implementing_Interfaces#Implementing_Interfaces_by_Delegation_.28Win32_only.29)

    type
      IMyInterface = interface
        procedure P1;
        procedure P2;
      end;
      TMyImplClass = class
        procedure P1;
        procedure P2;
      end;
      TMyClass1 = class(Class1, IMyInterface)
        FMyImplClass: TMyImplClass;
        property MyImplClass: TMyImplClass read FMyImplClass implements IMyInterface;
        procedure IMyInterface.P1 = MyP1;
        procedure MyP1;
      end;
      TMyClass2 = class(TInterfacedObject, IMyInterface)
        FMyImplClass: TMyImplClass;
        property MyImplClass: TMyImplClass read FMyImplClass implements IMyInterface;
        procedure P3;
        procedure P4;
      end;
    procedure TMyImplClass.P1;
         // ...
    procedure TMyImplClass.P2;
         // ...
    procedure TMyClass1.MyP1;
         // ...
    procedure TMyClass2.P3;
         // ...
    procedure TMyClass2.P4;
         // ...
    var
      MyClass: TMyClass1;
      MyInterface: IMyInterface;
    begin
      MyClass := TMyClass1.Create;
      MyClass.FMyImplClass := TMyImplClass.Create; //Error !!!! FMyImplClass is a read only    property !!!
      MyInterface := MyClass;
      MyInterface.P1;   // calls TMyClass1.MyP1;
      MyInterface.P2;   // calls TImplClass.P2;
    end;

Because I have an error at MyClass.FMyImplClass := TMyImplClass.Create; I tried to create FMyImplClass declaring constructor from TMyClass1 and TMyClass2 but don't work ok. Is there some other method to create FMyImplClass ?

Now I tried a solution that seem to work ok. Can there happen some hidden efects?

    type
      IMyInterface = interface
        procedure P1;
        procedure P2;
        procedure CreateFMyImplClass;
      end;
      TMyImplClass = class
        procedure P1;
        procedure P2;
      end;
      TMyClass1 = class(Class1, IMyInterface)
        FMyImplClass: TMyImplClass;
        property MyImplClass: TMyImplClass read FMyImplClass implements IMyInterface;
        procedure IMyInterface.P1 = MyP1;
        procedure MyP1;
        procedure CreateFMyImplClass;
      end;
      TMyClass2 = class(TInterfacedObject, IMyInterface)
        FMyImplClass: TMyImplClass;
        property MyImplClass: TMyImplClass read FMyImplClass implements IMyInterface;
        procedure P3;
        procedure P4;
        procedure CreateFMyImplClass;
      end;
    procedure TMyImplClass.P1;
         // ...
    procedure TMyImplClass.P2;
         // ...
    procedure TMyClass1.MyP1;
         // ...
    procedure TMyClass1.CreateFMyImplClass;
    begin
     FMyImplClass := TMyImplClass.Create;
    end;
    procedure TMyClass2.P3;
         // ...
    procedure TMyClass2.P4;
         // ...
    procedure TMyClass2.CreateFMyImplClass;
    begin
     FMyImplClass := TMyImplClass.Create;
    end;
    var
      MyInterface: IMyInterface;
    begin
      if WantRemote then
         MyInterface := TMyClass1.Create
      else
         MyInterface := TMyClass2.Create;
      MyInterface.CreateFMyImplClass;   // create FMyImplClass ;
      MyInterface.P2;   // calls TImplClass.P2;
    end;
Arioch 'The
  • 15,799
  • 35
  • 62
sorin
  • 23
  • 1
  • 6
  • Check this question: http://stackoverflow.com/questions/1276173/how-to-implement-multiple-inheritance-in-delphi – Andrey Adamovich Dec 20 '12 at 13:00
  • 1) make Class1 and Class2 inherit from TMYClassTest or 2) make TmyClassX no more implementing Interface1 directly, but instead add them a field of TMyClassTest and *delegate* their Interface1 to this field – Arioch 'The Dec 20 '12 at 13:07
  • 3
    You are out of luck. Delphi doesn't do multiple inheritance. On the other hand, inheritance is a grossly over-used and mis-used tool. Take this as a sign that composition is the way to go. – David Heffernan Dec 20 '12 at 13:11
  • Class1 is not my class and can't change anything on it. – sorin Dec 20 '12 at 13:13
  • TMyClass1 is not my class and can't change anything on it. TMyClass2 is my class and look like: class(TInterfacedObject, Interface1). I created TMyClass2 because I have a variabile like var x: Interface1; I need to use on some situations x := TMyClass1.Create and on other situations x := TMyClass2.Create; – sorin Dec 20 '12 at 13:17
  • for moment I deleted TMyClassTest and I implemented the code in TMyClass1 and TMyClass2 but is hard to keep sincronised the code. Now I use TMyClass2 instead of TMyClassTest. – sorin Dec 20 '12 at 13:19
  • In MyClass1 I can change/add only the methods from Interface1 – sorin Dec 20 '12 at 13:32
  • David, sorry for my english. What mean: composition is the way to go ? – sorin Dec 20 '12 at 13:34
  • Is the functionality of TInterfacedObject all you need to add? – David Heffernan Dec 20 '12 at 13:57
  • TMyClass1 = class(class1,Interface1) belong to a remote interface system for client server apps. I can add how many functionalities I want in Interface1 and I can implement those functionalities on TMyClass1. I have a variable like X := TMyClass1.Create; that I use when the client is connected to the server. The same variable X is used like X := TMyClass2.Create; when the client is not connected to the server. I created TMyClass2 = class(TInterfaceObject, Interface1); because X must have the Interface1 type (the declaration is like X: Interface1;). – sorin Dec 20 '12 at 17:30
  • I used copy/paste for methods from TMyClassTest and I implemented them on the TMyClass1 and TMyClass2 (and of course in the Interface1 I declared those methods). My app work ok but because I want to extend this app I need a solution, if is possible, to avoid the duplicate code from TMyClass1 and TMyClass2. TMyClassTest was deleted and I use the object X (with the methods that I added in the Interface1) instead of the object created with the old class TMyClassTest. – sorin Dec 20 '12 at 17:38
  • I tried to put the old code in a separate unit and reuse it on the TMyClass1 and TMyClass2 classes but was not possible because some procedures are events. – sorin Dec 20 '12 at 17:42
  • Arioch, can you point me to an example of your ideea ? – sorin Dec 20 '12 at 18:17
  • I still don't really understand your needs – David Heffernan Dec 20 '12 at 21:38
  • 1
    @sorin doing Google for "delphi interface delegation" shows this as top link: http://stackoverflow.com/questions/3483680 I think you'd better move that new common functions into some Interface0 type, and make Interface1 a child of Interface0. Then you make some TMyClasssBaseCommonTrait class, implementing Interface0, and two subclasssec TMyClass1InternalEngine(TMyClasssBaseCommonTrait) and TMyClass2InternalEngine(TMyClasssBaseCommonTrait) implementing (in different, TMyClassX-specific ways, the rest of Interface1(Interface0) API /// Delphi does not have Scala-like traits or Py-like mixins – Arioch 'The Dec 21 '12 at 07:09
  • @David, I have two classes that implement the same interface. A part of the interface is implemented identically in both classes. I want to find a way that not duplicate the code that is implemented identically on both classes – sorin Dec 21 '12 at 09:15
  • @Arioch, Yes I found on google a way to Implementing Interfaces by Delegation to a Class-Type Property. Seem to be ok, I will test now (example is for XE3 and I have D2006) but there seem to be a limitation i.e. win32 only (not a problem for the moment, maybe in the future). the link is [link](http://docwiki.embarcadero.com/RADStudio/XE3/en/Implementing_Interfaces#Implementing_Interfaces_by_Delegation_.28Win32_only.29) – sorin Dec 21 '12 at 11:31
  • @sorin i believe that means "it does not apply to Delphi.Net" but since .Net is long not supported that effectively means nothing. – Arioch 'The Dec 21 '12 at 11:40
  • I edited my problem description – sorin Dec 21 '12 at 13:35
  • Have a look at [this question](http://stackoverflow.com/questions/7719900/safe-way-in-delphi-for-a-form-to-distribute-interface-objects-tied-to-its-lifeti) and the use of TAggregateObject. I think it is as close as you can get in Delphi. – GolezTrol Dec 21 '12 at 13:39
  • I edited again my problem with a solution that seem to work ok. Can exists hide efects? also I'm interested about why in the first solution was not possible to run: MyClass.FMyImplClass := TMyImplClass.Create; (error because FMyImplClass is a read only property but is an example from Embracadero)? – sorin Dec 21 '12 at 14:18
  • I thank all of you for this help. Special thanks to Arioch that got me sent to correct solution. I think that now we should close this discussion but I don't know exactly how. Can I receive help again ? – sorin Dec 22 '12 at 08:29
  • *Interface = interface* u meant *IMYInterface = interface* ? – Arioch 'The Dec 22 '12 at 09:53
  • if u consider discussion complete - i summed my suggestions into one answer that u can accept. OTOH i think many participants in this discussion suggested the same in other words. – Arioch 'The Dec 22 '12 at 10:00

1 Answers1

3

Delphi does not have Scala-like traits or Python-like mixins, nor it support multiple inheritance a la C++.

If you cannot make Class1 and Class2 inherit from TMyClassTest, then perhaps you have to rely on interface delegation: make TMyClassX no more implementing Interface1 directly, but instead add them a field of TMyClassTest and delegate their Interface1 to this field.

I think you'd better

  1. move those new common functions into some Interface0 type
  2. make Interface1 inherited from Interface0
  3. make some TMyClassesBaseCommonTrait class, implementing Interface0
  4. make two subclasses TMyClass1InternalEngine(TMyClassesBaseCommonTrait) and TMyClass2InternalEngine(TMyClassesBaseCommonTrait) implementing (in different, TMyClassX-specific ways, the rest of Interface1(Interface0) API
  5. have TMyClassX classes internal private field of TMyClass2InternalEngine type doign real implemntation

Google for "delphi interface delegation" shows this as top link: Delphi: How delegate interface implementation to child object?

Community
  • 1
  • 1
Arioch 'The
  • 15,799
  • 35
  • 62