Najlepsze praktyki wdrażania MVVM i MVC w delphi Pascal

10

Jestem programistą Delphi pascal, używam najnowszej wersji Embarcadero delphi XE i chciałbym skorzystać z wzorców projektowych, takich jak kontroler widoku modelu i widok modelu.

Jednak wydaje się, że w Internecie nie ma zbyt wiele na temat najlepszych praktyk wykonywania tego w pascal. Większość przykładów, które mogę znaleźć, są w języku C #, a niektóre funkcje językowe nie są dostępne w języku pascal, co oznacza, że ​​być może będę musiał znaleźć sposoby na wdrożenie tych funkcji.

Próbuję dostosować kod z tego artykułu tutaj

Wymienię problemy, które napotykam

  • Typy zerowalne

Pascal nie ma typów zerowalnych jak C #, więc utworzyłem własne.

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;

w dziale implementacji

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;
  • Uzyskaj / ustaw właściwości

Teraz, gdy mam typ zerowalny, mogę tworzyć właściwości zerowalne. Jednak zawiera pewne zapachy kodowe

na przykład, jeśli utworzę

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

w dziale implementacji

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;

To dobrze, ale jeśli chodzi o użycie tych właściwości, nie mogę po prostu użyć

myFoo.Bar.Value: = 1;

Muszę użyć

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

Co jest nieco bardziej nieporządne. Podejrzewam, że nic nie mogę na to poradzić.

  • Referencje okólne

Lubię rozdzielać klasy na różne jednostki.

to znaczy: Struktura

oddzielenie interfejsu użytkownika od logiki sterowania oraz warstwy modelu i logiki danych.

Mogę mieć sytuację, w której 2 klasy mogą się nawzajem odnosić. Chociaż w większości przypadków chciałbym tego uniknąć, są sytuacje, w których jest to potrzebne.

na przykład

unit u_A;

interface

uses
  u_B
  ;

type 
  TA = class
    public
       Foo : TB;
  end;

implementation

end;

i inna jednostka

unit u_B;

interface

uses
  u_A
  ;

type 
  TB = class
    public
       Foo : TA;
  end;

implementation

end;

Ten kod jest zepsuty, ponieważ obie klasy obejmują się nawzajem i nie można tego zrobić w pascal. To nie jest taki problem w C #. Rozwiązania, które mogę wymyślić: 1. obejmują obie klasy w tej samej jednostce, chociaż jest to problem, jeśli nie uważam, że to pasuje do projektu. 2. Utwórz kolejny interfejs nadrzędny dla B i odziedzicz z niego B, a następnie to obejdzie. Chociaż jest to bałagan w przypadku tak prostego zadania.

  • Klasy statyczne

W Delphi nie ma żadnych klas statycznych, są one przydatne dla klas kontrolnych.

  • Najlepsze klasy kontenerów do użycia w Delphi

Obecnie używam TList i TObjectList w Generics.Collections Zostały one wprowadzone w Delphi XE Mam nadzieję, że są one najlepsze w użyciu, ponieważ delphi 7 nie miał dobrych opcji.

Nadal myślę o procedurach obsługi zdarzeń i wszelkich problemach, które mogą się tam pojawić. Być może są jeszcze inne kwestie, o których jeszcze nie myślałem.

Dziękuję za wszelkie porady.

sav
źródło
Pierwotnie zadałem to pytanie podczas przeglądu kodu, ale zasugerowano, żebym opublikował tutaj.
sav

Odpowiedzi:

9

Powinieneś spojrzeć na Spring4D, ponieważ zawiera on już typy zerowalne (podobna implementacja jak twoja z niewielkim dodatkowym przeciążeniem operatora) i znacznie potężniejsze typy kolekcji niż te w RTL. Są one również oparte na interfejsie, co jest bardzo przydatne, ponieważ nie musisz martwić się o zarządzanie przez całe życie, szczególnie podczas ich przekazywania.

W przypadku problemów z odsyłaczami sugeruję kodowanie interfejsów i używanie ich jako odniesienia w innej implementacji zamiast w dwóch implementacjach, które się znają.

Jeśli chodzi o część MVVM, możesz zajrzeć do DSharp, który ma pierwszą wersję portu Caliburn Micro dla Delphi. Jest to bardzo wczesny etap i mało udokumentowany, ale możesz mieć pewne pomysły, jak osiągnąć MVVM w Delphi przy użyciu luźno sprzężonego GUI i logiki biznesowej związanej z powiązaniami danych. Magazyn Blaise Pascal miał dwa artykuły na ten temat, jeśli jesteś bardziej zainteresowany.

PS Chyba masz na myśli, że używasz XE6, ponieważ jest to najnowsza wersja.

Stefan Glienke
źródło