Search code examples
oopdelphiinterface

Delphi OOP Interface, delegated method, why and when is which one called?


I am playing around with Interfaces.

unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  IOrcs = interface
  ['{89B86797-9F86-48B8-8D0B-01A78C2CA523}']
    function Enemies : string;
  end;
  IHumans = interface
  ['{D32C39A3-C654-4078-BD5A-0D3793530FB0}']
    function Allies : string;
  end;

  TOrc = class (TInterfacedObject, IOrcs)
    function Enemies : string;
  end;

  THuman = class (TInterfacedObject, IHumans)
    function Allies : string;
  end;

  TElves = class (TInterfacedObject, IHumans,IOrcs)
  private
    fOrc : IOrcs;
  public
    constructor Create;
    function Enemies : string;
    function Allies : string;

    property Orc : IOrcs read fOrc implements IOrcs;
  end;


  TForm1 = class(TForm)
    btnHumans: TButton;
    btnOrcs: TButton;
    ListBox1: TListBox;
    btnElves: TButton;
    procedure btnHumansClick(Sender: TObject);
    procedure btnOrcsClick(Sender: TObject);
    procedure btnElvesClick(Sender: TObject);
  private
    { Private declarations }
    procedure Log ( str : string );
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TOrc }

function TOrc.Enemies: string;
begin
  Result := 'Our Enemies Humans';
end;

{ THumans }

function THuman.Allies: string;
begin
  Result := 'Our Allies Elves';
end;

{ TForm1 }

procedure TForm1.btnElvesClick(Sender: TObject);
var Allied : IHumans;
    Horde : IOrcs;

    Test : TElves;
begin

  Allied := TElves.Create;

  Log('IHumans');

  Log(Allied.Allies);

  Log('IOrcs');

  Horde := Allied as IOrcs;

  Log(Horde.Enemies);

  Log('TElves.Create');

  Test := TElves.Create;

  Log(test.Allies);
  Log(test.Enemies);
end;

procedure TForm1.btnHumansClick(Sender: TObject);
var Allied : IHumans;
begin

  Allied := THuman.Create;

  Log(Allied.Allies);


end;

procedure TForm1.btnOrcsClick(Sender: TObject);
var Horde : IOrcs;
begin

  Horde := TOrc.Create;

  Log(Horde.Enemies);
end;

procedure TForm1.Log(str: string);
begin
  ListBox1.Items.Add(str);
end;

{ TElves }

function TElves.Allies: string;
begin
  Result:='Wood Elves';
end;

constructor TElves.Create;
begin
  fOrc := TOrc.Create;
end;

function TElves.Enemies: string;
begin
  Result:='Orcs and Dwarwes';
end;

end.

The question here is regarding TElves.

I have a function Enemies(), and I have a property Orc which implements IOrcs, so I guess that is why the Enemies() function is called from IOrcs instead of locally.

If I comment out the property, the local Enemies() function is called.

I obviously do not understand the use case of this. Maybe I am doing this completely wrong. But when using IInterface instead of TClass, is there a way to call the local function?


Solution

  • The method is called from TOrcs because of the implements IOrcs in:

    property Orc : IOrcs read fOrc implements IOrcs;
    

    The implements directive allows you to delegate implementation of an interface to a property in the implementing class.

    It mean that the implementation of IOrcs in your class will use fOrc

      TElves = class (TInterfacedObject, IHumans,IOrcs)
      private
        fOrc : IOrcs;
      public
        constructor Create;
        function Enemies : string;
        function Allies : string;
    
        property Orc : IOrcs read fOrc;
      end;