Search code examples
delphiinterfacespring4d

How use multi interface class in Spring4D


I'm just learning Spring4D and i have one question. If class implement only one interface its all clear:

    IWeapon = interface
        ['{E679EDA6-5D43-44AD-8F96-3B5BD43A147B}']
        procedure Attack;
    end;

    TSword = class(TInterfacedObject, IWeapon)
    public
        procedure Attack;
    end;

    GlobalContainer.RegisterType<TSword>.Implements<IWeapon>('sword');
    sword := ServiceLocator.GetService<IWeapon>('sword');

and im really happy now, I have sword and i dont need to Free it.

but if class implements two or more interfaces:

    IWeapon = interface
        ['{E679EDA6-5D43-44AD-8F96-3B5BD43A147B}']
        procedure Attack;
    end;

    IShield = interface
        ['{B2B2F443-85FE-489C-BAF4-538BB5B377B3}']
        function Block: Integer;
    end;

    TSpikedShield = class(TInterfacedObject, IWeapon, IShield)
    public
        function Block: Integer;
        procedure Attack;
    end;

    GlobalContainer.RegisterType<TSpikedShield>.Implements<IWeapon>.Implements<IShield>;

I can ask ServiceLocator for an instance of TSpikedShield but i need choose one IWeapon or IShield. But I want use it in two ways(or i shouldn't want?) like:

spikedShield.Attack;
spikedShield.Block;

So if I good undestand, I have to create instance of TSpikedShiled directly(i mean without interface).

function MakeSpikedShield: TSpickedShield;
begin
    result := TSpickedShield.Create;
end;

There is any way to use this class but with automagical Free?

(there won't be problem if interfaces could implement multi interfeces but its not allowed in delphi)

Edited: maybe somethink like that?

ISpikedSield = interface
    function AsWeapon: IWeapon;
    function AsShield: IShield;
end;
TSpikedShield = class(TInterfacedObject, ISpikedShield)

Solution

  • There won't be problem if interfaces could implement multi interfaces but it's not allowed in Delphi

    That is the exact cause of the problem.

    I would just make an ISpikedShield interface that has the methods of IWeapon and IShield and making sure that every class that implements ISpikedShield also explicitly implements IWeapon and IShield (this is what the compiler basically does for you in C# for example where an interface can inherit from multiple other interfaces).

    You then cannot assign an ISpikedShield to an IWeapon and IShield but using as operator will work because the class behind implements them.

    However I am not sure if there is not a misconception in your architecture because if you think further there won't be a class that has an ISpikedShield as dependency but rather an IWeapon and/or IShield. Some game code would then check if your IShield supports ICanAttack to do an additional hit apart from those you can do with your IWeapon.