Mejores prácticas para implementar MVVM y MVC en Delphi Pascal

10

Soy un programador pascal de Delphi, utilizo el último Embarcadero delphi XE, y me gustaría aprovechar los patrones de diseño como el controlador de vista de modelo y la vista de modelo.

Sin embargo, no parece haber mucho en la web sobre las mejores prácticas para hacer esto en pascal. La mayoría de los ejemplos que puedo encontrar están en C # y algunas de las características del lenguaje no están presentes en pascal, lo que significa que quizás tenga que encontrar formas de implementar esas características.

Estoy tratando de adaptar el código de este artículo aquí.

Voy a enumerar los problemas que estoy enfrentando

  • Tipos anulables

Pascal no tiene tipos anulables como C #, así que he creado el mío.

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;

en la sección de implementación

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;
  • Obtener / Establecer para propiedades

Ahora que tengo un tipo anulable, puedo crear propiedades anulables. Sin embargo, viene con algunos olores de código

por ejemplo si creo

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

en la sección de implementación

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;

Esto está bien, pero cuando se trata de usar estas propiedades, no puedo simplemente usar

myFoo.Bar.Value: = 1;

Tengo que usar

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

Lo cual es un poco más desordenado. Supongo que no hay nada que pueda hacer al respecto.

  • Referencias circulares

Me gusta separar las clases en diferentes unidades.

es decir: estructura

manteniendo la interfaz de usuario separada de la lógica de control y el modelo y la capa de lógica de datos.

Puedo tener una situación en la que 2 clases pueden referenciarse entre sí. Si bien esta es una situación que en su mayor parte me gustaría evitar, hay ocasiones en que esto es necesario.

por ejemplo

unit u_A;

interface

uses
  u_B
  ;

type 
  TA = class
    public
       Foo : TB;
  end;

implementation

end;

y otra unidad

unit u_B;

interface

uses
  u_A
  ;

type 
  TB = class
    public
       Foo : TA;
  end;

implementation

end;

Este código está roto porque las dos clases se incluyen entre sí y esto no se puede hacer en pascal. Esto no es un problema en C #. Soluciones en las que puedo pensar: 1. incluir ambas clases en la misma unidad, aunque esto es un problema si no creo que esto se adapte al diseño. 2. Cree otra interfaz principal para B y herede B de eso, entonces esto lo evita. Aunque esto es complicado para una tarea tan simple.

  • Clases estáticas

No hay clases estáticas en Delphi, estas son útiles para las clases de control.

  • Las mejores clases de contenedores para usar en Delphi

Actualmente estoy usando TList y TObjectList en genéricos. Colecciones Se introdujeron en Delphi XE. Espero que sean las mejores para usar, ya que delphi 7 no parecía tener buenas opciones.

Todavía estoy pensando en los controladores de eventos y cualquier problema que pueda surgir allí. Quizás hay otros problemas que aún no he pensado.

Gracias por cualquier consejo

sav
fuente
Originalmente hice esta pregunta sobre la revisión del código, pero se sugirió que publique aquí.
Sav

Respuestas:

9

Debería examinar Spring4D ya que ya contiene tipos anulables (implementación similar a la suya con una pequeña sobrecarga adicional del operador) y tipos de colección mucho más potentes que los de RTL. También están basados ​​en interfaces, lo cual es muy útil porque no tiene que preocuparse por la administración de por vida, especialmente al pasarlos.

Para problemas de referencias cruzadas, sugiero la codificación contra interfaces y usarlas como referencia en otra implementación en lugar de que 2 implementaciones se conozcan entre sí.

En cuanto a la parte MVVM, puede buscar en DSharp, que tiene una primera versión de un puerto Caliburn Micro para Delphi. Es una etapa muy temprana y apenas documentada, pero puede obtener algunas ideas sobre cómo lograr MVVM en Delphi utilizando una GUI débilmente acoplada y una lógica empresarial conectada con enlaces de datos. La revista Blaise Pascal tenía dos artículos al respecto si está más interesado.

PD: Supongo que te refieres a que estás usando XE6, ya que es la última versión.

Stefan Glienke
fuente