Как использовать мультиинтерфейсный класс в Spring4D

Я только учусь Spring4D, и у меня есть один вопрос. Если класс реализует только один интерфейс, все ясно:

    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');

и теперь я действительно счастлив, у меня есть меч, и мне не нужно освобождать его.

но если класс реализует два или более интерфейса:

    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>;

Я могу попросить ServiceLocator для экземпляра TSpikedShield, но мне нужно выбрать один IWeapon или IShield. Но я хочу использовать его двумя способами (или не хочу?), Например:

spikedShield.Attack;
spikedShield.Block;

Так что, если я хорошо понимаю, я должен создать экземпляр TSpikedShiled напрямую (я имею в виду без интерфейса).

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

Есть ли способ использовать этот класс, но с автоматическим Free?

(не будет проблем, если интерфейсы могут реализовывать множественные помехи, но это не разрешено в Delphi)

Отредактировано: может быть, что-то подобное?

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

1 ответ

Решение

Там не будет проблем, если интерфейсы могут реализовать несколько интерфейсов, но это не разрешено в Delphi

Это точная причина проблемы.

Я бы просто сделал ISpikedShield интерфейс, который имеет методы IWeapon а также IShield и убедившись, что каждый класс, который реализует ISpikedShield также явно реализует IWeapon а также IShield (это то, что компилятор в основном делает для вас в C#, например, где интерфейс может наследоваться от нескольких других интерфейсов).

Затем вы не можете назначить ISpikedShield для IWeapon а также IShield но использование в качестве оператора будет работать, потому что класс позади реализует их.

Однако я не уверен, что в вашей архитектуре нет неправильного представления, потому что, если вы будете думать дальше, не будет класса, который имеет ISpikedShield как зависимость, а скорее IWeapon и / или IShield, Некоторый игровой код будет проверять, если ваш IShield опоры ICanAttack сделать дополнительный удар, кроме тех, которые вы можете сделать с вашим IWeapon,

Другие вопросы по тегам