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

人走茶凉 提交于 2019-12-23 13:15:27

问题


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?


回答1:


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.




回答2:


Class helpers are useful for modifying classes you can't get at the source to. If you're the author of class TC1, and you would be able to make the necessary changes by introducing a class helper for TC1, then why not just modify TC1.Func1, and then you're done? That should work.




回答3:


You can make a wrapper class following the decorator pattern to describe the special tasks that need to occur when your program is operating in analogue mode. It can hold an instance of your digital component and call that component's methods after performing its own tasks.

type
  TAnalogueDecorator = class(TC1)
  private
    FComponent: TC1;
  public
    constructor Create(Wrapped: TC1);
    destructor Destroy; override;

    function Func1: Integer; override;
  end;

constructor TAnalogueDecorator.Create(Wrapped: TC1);
begin
  inherited Create;
  FComponent := Wrapped;
end;

destructor TAnalogueDecorator.Destroy;
begin
  FComponent.Free;
  inherited;
end;

function TAnalogueDecorator.Func1: Integer;
begin
  SaveActionData;
  Result := FComponent.Func1;
end;

Notice how there's no need to check your x condition beforehand. Instead of checking it each time you call any method, you can check it once before wrapping the digital component with the analogue one. Now all the places where you originally called Func1 directly on the digital class get detoured to the analogue class's methods first.



来源:https://stackoverflow.com/questions/2362844/how-to-encapsulate-different-classes-within-one-class-mantaining-their-unique-me

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!