Как использовать мультиинтерфейсный класс в 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
,