Лучшие практики для реализации MVVM и MVC в Delphi Pascal

10

Я программист на Delphi Pascal, я использую последнюю версию Embarcadero Delphi XE, и я хотел бы воспользоваться преимуществами шаблонов проектирования, таких как контроллер представления модели и представление представления модели.

Тем не менее, в Интернете, кажется, не так много о лучших методах сделать это на паскале. Большинство примеров, которые я могу найти, находятся на C #, а некоторые языковые функции отсутствуют на паскале, что означает, что мне, возможно, придется искать способы реализации этих функций.

Я пытаюсь адаптировать код из этой статьи здесь

Я перечислю проблемы, с которыми я сталкиваюсь

  • Обнуляемые типы

В Паскале нет обнуляемых типов, как в C #, поэтому я создал свой собственный.

TNullable<T> = record
    strict private
      fHasValue : boolean;
      fValue : T;
      function GetValue:T;
      procedure SetValue(newValue : T);
    public
      property HasValue : boolean read fHasValue;
      property Value : T read GetValue write SetValue;
      procedure SetToNull;
    end;

в разделе реализации

function TNullable<T>.GetValue:T;
begin
    if fHasValue then
    begin
        Result := fValue;
    end
    else raise Exception.Create('Value Not Set');
end;

procedure TNullable<T>.SetValue(newValue : T);
begin
    fValue := newValue;
    fHasValue := true;
end;

procedure TNullable<T>.SetToNull;
begin
    fHasValue := false;
end;
  • Получить / установить свойства

Теперь, когда у меня есть обнуляемый тип, я могу создавать обнуляемые свойства. Однако он имеет некоторые запахи кода.

например, если я создаю

    TFoo = class
      private
        function GetBar:TNullable<Integer>;
        procedure SetBar(x:TNullable<Integer>);
      public 
        property Bar : TNullable<Integer> read GetBar write SetBar;

в разделе реализации

function TFoo.GetBar:TNullable<Integer>;
begin
    if **valueExists** then
    begin
        Result.Value := **the value**
    end else
    begin
        Result.SetToNull;
    end;
end;

procedure TFoo.SetBar(x:TNullable<Integer>);
begin
    if X.hasValue then
    begin
        //Store/show value here
    end else
    begin
        //handle null assignment here
    end;
end;

Это хорошо, но когда дело доходит до использования этих свойств, я не могу просто использовать

myFoo.Bar.Value: = 1;

Я должен использовать

var 
    myBar : TNullable<Integer>;
begin
    myBar.Value := 1;
    myFoo.Bar := myBar;
end;

Что немного сложнее. Я полагаю, что я ничего не могу с этим поделать.

  • Циркулярные ссылки

Мне нравится разделять классы на разные единицы.

то есть: структура

поддержание интерфейса пользователя отдельно от логики управления и уровня логики модели и данных.

У меня может быть ситуация, когда 2 класса могут ссылаться друг на друга. Хотя в большинстве случаев я хотел бы избежать этой ситуации, бывают случаи, когда это необходимо.

например

unit u_A;

interface

uses
  u_B
  ;

type 
  TA = class
    public
       Foo : TB;
  end;

implementation

end;

и другой блок

unit u_B;

interface

uses
  u_A
  ;

type 
  TB = class
    public
       Foo : TA;
  end;

implementation

end;

Этот код не работает, потому что два класса включают друг друга, и это не может быть сделано на паскале. Это не такая проблема в C #. Решения, которые я могу придумать: 1. включить оба класса в один и тот же модуль, хотя это проблема, если я не думаю, что это соответствует дизайну. 2. Создайте другой родительский интерфейс для B и унаследуйте B от этого, тогда это обойдется. Хотя это грязно для такой простой задачи.

  • Статические классы

В Delphi нет статических классов, они полезны для управляющих классов.

  • Лучшие классы контейнеров для использования в Delphi

В настоящее время я использую TList и TObjectList в Generics.Collections. Они были представлены в Delphi XE. Я надеюсь, что они лучше всего подходят, поскольку Delphi 7, похоже, не имеет хороших вариантов.

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

Спасибо за любой совет.

SAV
источник
Первоначально я задавал этот вопрос в обзоре кода, но было предложено разместить здесь.
SAV

Ответы:

9

Вы должны взглянуть на Spring4D, так как он уже содержит обнуляемые типы (аналогичная реализация, как у вас, с небольшой дополнительной перегрузкой операторов) и гораздо более мощные типы коллекций, чем в RTL. Они также основаны на интерфейсе, что очень удобно, потому что вам не нужно беспокоиться об управлении жизненным циклом, особенно при их передаче.

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

Что касается части MVVM, вы можете взглянуть на DSharp, который имеет первую версию порта Caliburn Micro для Delphi. Это очень ранняя стадия и вряд ли документирована, но вы можете получить некоторые идеи о том, как создать MVVM в Delphi, используя слабосвязанный графический интерфейс и бизнес-логику, связанную с привязками данных. В журнале «Блез Паскаль» было две статьи на этот счет, если вам больше интересно.

PS Я думаю, вы имеете в виду, что вы используете XE6, так как это последняя версия.

Стефан Глиенке
источник