delphimultiple-inheritanceclass-helpers

How to encapsulate different classes within one class mantaining their unique methods? (multiple inheritance in delphi?)


I'm currently rewriting a free educational digital circuit simulator to add inertiality to its features. My problem is how to dispatch events to original classes adding a pre-elaboration to them. I have something like this:

TC1 = class
  ID: integer;
  Connections : array [integer] of Pin;
  function Func1; virtual;
  function FuncN;
end;

TC2-1 = class (TC1)
  function Func1; override;
  function My1Func();
end;

TC2-n = class (TC1)
  function Func1; override;
  function MyNFunc();
end;


TContainer = class
  C1 : TC1;
  function ContFunc;
end;

function Container.ContFunc;
begin
    c1.Func1;
end;

Now this means that ContFunc call C2.Func1 as I wish, specializing behaviour of more than 300 components inheriting form TC1.

But now I have to add some special operations (equal for all component descendants from TC1 every time Func1 is called, and chosing during that operations if I have to call TC2-n.Func1 or not (after changing some property of ancestor TC1. Is there a way to do that cleanly, without changing all descendants of TC1? Can I use a helper class (deprecated?) like this:

TH = class helper of TC1
  function Func1 virtual; override;
end;

function TH.Func1;
begin
  if x then TC2.Func1 else SaveActionData; 
end

If I add TH, when TContainer call Func1, who is called? It call TC2.Func1 and not TH.Func1 as I wished?. Is there a way to override descenants method Func1 without writing an helper class for any single one (they will do all the same operations, meaning exactly equal code)? It is possible to call from TH the 300 descendant functions Func1 of TC2-n ?

In other words, I'm trying to find a way to obtain a call like this by Tcontainer call to c1.Func1;:

NewFunc1 (equal for all TC1 descendants) who call TC2.Func1 (different for any descendant of TC1).

Anyone can suggest a way to do that?


Solution

  • You have some tasks that need to be performed whenever someone calls Func1, regardless of what descendants have chosen to do in their overridden methods. This is a job for the template method pattern.

    Give the base class a public non-virtual method Func1 that performs the operations you need and then invokes a protected virtual method. The descendants can override that virtual method, but anyone using the class can only call the public non-virtual method.

    type
      TC1 = class
      protected
        function InternalFunc1: Integer; virtual; // abstract?
      public
        function Func1: Integer;
      end;
    
    function TC1.Func1;
    begin
      if x then
        Result := InternalFunc1
      else
        Result := SaveActionData; 
    end;
    

    Now descendants can override InternalFunc1, and the base class will make sure it gets called only when appropriate.

    type
      TC2 = class(TC1)
      protected
        function InternalFunc1: Integer; override;
      end;
    

    You'll need to rename your current Func1 function in all your 300 descendant classes. The IDE's refactoring tools might be able to help with that.