Это немного особый случай интерфейсов, где класс реализует несколько версий одного и того же интерфейса, т.е. что-то вроде следующего
IBase = interface
procedure Foo;
end;
ISub = interface (IBase)
procedure Bar;
end;
ISpecialBase = interface (IBase) end;
ISpecialSub = interface (ISub) end;
TMyClass = class(TInterfacedObject, ISpecialBase, ISpecialSub)
procedure SpecialFoo1;
procedure SpecialFoo2;
procedure SpecialBar;
procedure ISpecialBase.Foo = SpecialFoo1;
procedure ISpecialSub.Foo = SpecialFoo2;
procedure ISpecialSub.Bar = SpecialBar;
function GetTheRightOne(parameters) : IBase;
end;
...
function TMyClass.GetTheRightOne(parameters) : IBase;
begin
if (something complex depending on parameters) then
Result := ISpecialBase(Self)
else Result := ISpecialSub(Self)
end;
конечно, в реальном случае имеется около десятка ISpecialXxxx.
Очень важно иметь только один экземпляр, т.е. Я хочу, чтобы избежать необходимости создавать адаптеры или фиктивные экземпляры только для того, чтобы отложить реализацию ISpecialXxxx, поскольку единственная цель предыдущего проекта - именно то, чтобы один экземпляр обработал много выдающихся интерфейсов (т.е. RefCount TMyClass может попасть в тысячные).
Теперь проблема в том, что GetTheRightOne() возвращает IBase, но в какой-то момент я хочу проверить, может ли этот IBase быть передан в ISub.
Есть ли способ сделать это с помощью указанной выше формы объявления?
В один из способов можно добавить
function GetSub : ISub;
для IBase, но это действительно делает дизайн намного более тяжелым, так как это должно быть реализовано для каждого ISpecialXxxx и будет избыточным с "наследованием" ISpecialXxxx, поэтому я ищу более элегантное решение (при условии, что он существует).
(У меня есть другие "раздутые" решения, поэтому я действительно хочу подчеркнуть, что я ищу решение без вздутия)
изменить: несколько подробнее
- В исходном коде существуют GUID (но их недостаток не является тем, что вызывает трудности).
- Поддержка и QueryInterface не работают, поскольку ISpecialXxx необходимо иметь несколько версий интерфейса для каждого класса, ISub не указан явно, и поэтому не найден. Тем не менее, оба работают с адаптером/фиктивным классом для отсрочки интерфейса (так как ISub может быть явно указан)
edit2: если вы хотите детали gory
Отметьте https://code.google.com/p/dwscript/source/browse/trunk/Source/dwsJSONConnector.pas (r2492), класс TdwsJSONConnectorType и интерфейс IJSONLow, цель состоит в том, чтобы обнаружить IConnectorFastCall от него, когда он прошел как IConnectorCall и, таким образом, имел возможность использовать LowFastCall, а не LowCall.
Обнаружение должно происходить в TConnectorCallExpr.AssignConnectorSym, строка 294, где в настоящее время имеется QueryInterface.
Обратите внимание, что QueryInterface работает в случае TdwsJSONIndexReadCall и TdwsJSONIndexWriteCall, поскольку они реализуют IConnectorCall и IConnectorFastCall из разных классов и экземпляров. Но этого я бы хотел избежать.
Конечно, целью было бы свернуть все в класс ConnectorType (один класс, один экземпляр), и для каждого интерфейса конкретный класс ConnectorType должен быть свободен для реализации IConnectorCall или IConnectorFastCall.