Как избежать приведения при передаче объектов через библиотечный код (в Delphi) - PullRequest
4 голосов
/ 30 марта 2009

При проектировании библиотек я часто прибегаю к следующему шаблону, который мне не нравится, так как он приводит к большому количеству приведения типов.

Основной шаблон:
Код, использующий библиотеку, передает объект в библиотеку, затем библиотека возвращает объект обратно вызывающему коду. Вызывающий код вынужден приводить объект, поскольку библиотека возвращает общий тип. (Приведенный ниже пример кода)

Библиотека определяет следующие объекты и функции:

TThing = Class
End;

TThingProcessor = Class
Public
    Function  CreateThing : TThing; Virtual; Abstract;
    Procedure ProcessThing (Thing : TThing); Virtual; Abstract;
End;

Procedure DoEverything (Processor : TThingProcessor);

Затем вызывающий код использует библиотеку, переопределяя объекты и вызывая DoEverything следующим образом -

TMyThing = Class(TThing)
Public
    X : Integer;
End;

TMyThingProcessor = Class(TThingProcessor)
Public
    XSum : Integer;

    Function  CreateThing : TThing; Override;
    Procedure ProcessThing (Thing : TThing); Override;
End;

Function TMyThingProcessor.CreateThing : TThing;
Begin
    Result := TMyThing.Create;
End;

Procedure TMyThingProcessor.ProcessThing (Thing : TThing);
Begin
    XSum := XSum + (Thing As TMyThing).X;
    //Here is the problem, the caller is forced to cast to do anything
End;

Класс процессора также является фабрикой TThing. Библиотека гарантирует, что она будет только передавать TThings соответствующему создателю TThingProcessor, поэтому она работает, но не является типобезопасной. Хотя приведенный выше код немного глуп, поскольку на самом деле он ничего не делает, он показывает, почему ProcessThing нельзя просто перевести на TThing и быть полиморфным - переменную XSum необходимо обновить.

Как я могу реструктурировать код, чтобы приведение не было необходимости? Мне нужно хранить код библиотеки отдельно, но я могу принимать любой тип.

Edit: Из-за предложения изменено жесткое приведение к приведению, так что оно будет по крайней мере генерировать исключение вместо сбоя в случае несовпадения типов

Ответы [ 3 ]

3 голосов
/ 30 марта 2009

Вы используете Delphi 2009? Это отличное применение для дженериков. Измените свои декларации на:

TThingProcessor<T: TThing> = Class
Public
    Function  CreateThing : T; Virtual; Abstract;
    Procedure ProcessThing (Thing : T); Virtual; Abstract;
End;


TMyThingProcessor = Class(TThingProcessor<TMyThing>)
Public
    XSum : Integer;

    Function  CreateThing : TMyThing; Override;
    Procedure ProcessThing (Thing : TMyThing); Override;
End;

Больше нет кастинга.

3 голосов
/ 30 марта 2009

Вы должны реструктурировать свой код. Если вы много работаете над созданием «TThing», у него должен быть класс предков с методом процесса irs, объявленным как виртуальный, тогда вы просто работаете с предком. Как правило, всегда можно определить общий «базовый класс», когда вы выполняете аналогичные вызовы для очень разных классов. Если вы не можете создать структуру класса, подобную этой, используйте интерфейс, чтобы определить требования к обработке и привязать этот интерфейс к вашему TThing.

В последнем случае, когда вы не можете избежать приведения, используйте следующее для простоты чтения и отладки ...

procedure Something( ASender : TObject );
var
  MyThing : TMyThing;
begin
  MyThing := ASender as TMyThing;
  MyTHing.DoSomething;
  MyThing.DoSomethingElse;
end;
1 голос
/ 30 марта 2009

Если TMyThingProcessor будет принимать только объекты TMyThing и базовые объекты TThing не будут работать, не пытайтесь делать это полиморфно. Объявите ProcessThing с директивой reintroduce; вместо директивы override; .

Кроме того, если они у вас есть, функции Generics в Delphi 2009 очень помогают в сокращении ложных типов в определенных ситуациях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...