Práticas recomendadas para implementar MVVM e MVC no delphi Pascal

10

Sou um programador Delphi Pascal, uso o mais recente Embarcadero delphi XE e gostaria de tirar proveito de padrões de design, como Model view controller e model view view-model.

No entanto, não parece haver muito na web sobre as melhores práticas para fazer isso em pascal. A maioria dos exemplos que posso encontrar está em C # e alguns dos recursos de idioma não estão presentes no pascal, o que significa que talvez seja necessário encontrar maneiras de implementar esses recursos.

Estou tentando adaptar o código deste artigo aqui

Vou listar os problemas que estou enfrentando

  • Tipos anuláveis

Pascal não tem tipos anuláveis ​​como o C #, então eu criei os meus.

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;

na seção de implementação

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;
  • Obter / definir propriedades

Agora que tenho um tipo anulável, posso criar propriedades anuláveis. No entanto, ele vem com alguns odores de código

por exemplo, se eu criar

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

na seção de implementação

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;

Isso é bom, mas quando se trata de usar essas propriedades, não posso simplesmente usar

myFoo.Bar.Value: = 1;

Eu tenho que usar

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

O que é um pouco mais confuso. Suponho que não haja nada que eu possa fazer sobre isso.

  • Referências circulares

Eu gosto de separar as aulas em diferentes unidades.

ou seja: estrutura

mantendo a interface do usuário separada da lógica de controle e da camada lógica de modelo e dados.

Eu posso ter uma situação em que duas classes podem se referir uma à outra. Embora essa seja uma situação que, na maioria das vezes, eu gostaria de evitar, há ocasiões em que isso é necessário.

por exemplo

unit u_A;

interface

uses
  u_B
  ;

type 
  TA = class
    public
       Foo : TB;
  end;

implementation

end;

e outra unidade

unit u_B;

interface

uses
  u_A
  ;

type 
  TB = class
    public
       Foo : TA;
  end;

implementation

end;

Esse código está quebrado porque as duas classes se incluem e isso não pode ser feito em pascal. Este não é um problema no C #. As soluções em que consigo pensar: 1. incluem as duas classes na mesma unidade, embora isso seja um problema se eu não achar que isso se adapte ao design. 2. Crie outra interface pai para B e herda B disso, então isso é contornado. Embora isso seja confuso para uma tarefa tão simples.

  • Classes estáticas

Não há classes estáticas no Delphi, elas são úteis para classes de controle.

  • Melhores classes de contêineres para usar no Delphi

Atualmente, estou usando TList e TObjectList em Generics.Collections Eles foram introduzidos no Delphi XE. Espero que sejam os melhores para usar, pois o delphi 7 não parecia ter boas opções.

Ainda estou pensando nos manipuladores de eventos e em quaisquer problemas que possam surgir por lá. Talvez haja outras questões em que ainda não pensei.

Obrigado por qualquer conselho.

sav
fonte
Eu originalmente fiz essa pergunta na revisão de código, mas foi sugerido que eu publicasse aqui.
sav

Respostas:

9

Você deve procurar no Spring4D, pois ele já contém tipos anuláveis ​​(implementação semelhante à sua com uma sobrecarga extra de operador) e tipos de coleção muito mais poderosos do que aqueles na RTL. Eles também são baseados em interface, o que é muito útil, porque você não precisa se preocupar com o gerenciamento da vida útil, especialmente ao distribuí-los.

Para problemas de referência cruzada, sugiro codificar contra interfaces e usá-las como referência em outra implementação, em vez de duas implementações que se conhecem.

Quanto à parte MVVM, você pode procurar no DSharp, que possui uma primeira versão de uma porta Caliburn Micro para Delphi. É um estágio muito inicial e dificilmente documentado, mas você pode ter algumas idéias de como obter o MVVM no Delphi usando a GUI e a lógica de negócios fracamente acopladas conectadas às ligações de dados. A revista Blaise Pascal tinha dois artigos, se você estiver mais interessado.

PS Acho que você quer dizer que está usando o XE6, pois essa é a versão mais recente.

Stefan Glienke
fonte