Meilleures pratiques pour implémenter MVVM et MVC dans Delphi Pascal

10

Je suis un programmeur Pascal Delphi, j'utilise le dernier Embarcadero delphi XE, et je voudrais profiter des modèles de conception tels que le contrôleur de vue du modèle et le modèle de vue du modèle.

Cependant, il ne semble pas y avoir beaucoup sur le web sur les meilleures pratiques pour le faire en pascal. La plupart des exemples que je peux trouver sont en C # et certaines fonctionnalités du langage ne sont pas présentes dans pascal, ce qui signifie que je devrai peut-être trouver des moyens de mettre en œuvre ces fonctionnalités.

J'essaie d'adapter le code de cet article ici

Je vais lister les problèmes auxquels je suis confronté

  • Types nullables

Pascal n'a pas de types Nullable comme C #, donc j'ai créé le mien.

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;

dans la section de mise en œuvre

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;
  • Obtenir / définir pour les propriétés

Maintenant que j'ai un type Nullable, je peux créer des propriétés Nullable Cependant, il est livré avec quelques odeurs de code

par exemple si je crée

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

dans la section de mise en œuvre

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;

C'est bien mais quand il s'agit d'utiliser ces propriétés, je ne peux pas simplement utiliser

myFoo.Bar.Value: = 1;

Je dois utiliser

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

Ce qui est un peu plus compliqué. Je suppose que je ne peux rien y faire.

  • Références circulaires

J'aime séparer les classes en différentes unités.

c'est à dire: structure

garder l'interface utilisateur distincte de la logique de contrôle et de la couche logique de modèle et de données.

Je peux avoir une situation où 2 classes peuvent se référencer. Bien que ce soit une situation que j'aimerais éviter pour la plupart, il y a des occasions où cela est nécessaire.

par exemple

unit u_A;

interface

uses
  u_B
  ;

type 
  TA = class
    public
       Foo : TB;
  end;

implementation

end;

et une autre unité

unit u_B;

interface

uses
  u_A
  ;

type 
  TB = class
    public
       Foo : TA;
  end;

implementation

end;

Ce code est cassé car les deux classes s'incluent et cela ne peut pas être fait en pascal. Ce n'est pas un tel problème en C #. Solutions auxquelles je peux penser: 1. inclure les deux classes dans la même unité, bien que ce soit un problème si je ne pense pas que cela convient à la conception. 2. Créez une autre interface parent pour B et héritez-en de B, puis cela contourne. Bien que ce soit compliqué pour une tâche aussi simple.

  • Classes statiques

Il n'y a pas de classes statiques dans Delphi, elles sont utiles pour les classes de contrôle.

  • Meilleures classes de conteneurs à utiliser dans Delphi

J'utilise actuellement TList et TObjectList dans Generics.Collections Ils ont été introduits dans Delphi XE J'espère que ce sont les meilleurs à utiliser car delphi 7 ne semblait pas avoir de bonnes options.

Je pense toujours aux gestionnaires d'événements et à tout problème qui pourrait survenir. Il y a peut-être d'autres problèmes auxquels je n'ai pas encore pensé.

Merci pour tout conseil.

sav
la source
J'ai initialement posé cette question sur la révision du code, mais il m'a été suggéré de poster ici.
enregistrer

Réponses:

9

Vous devriez examiner Spring4D car il contient déjà des types nullables (implémentation similaire à la vôtre avec un peu de surcharge d'opérateur supplémentaire) et des types de collection bien plus puissants que ceux de la RTL. Ils sont également interfacés, ce qui est très pratique car vous n'avez pas à vous soucier de la gestion de la vie, en particulier lorsque vous les passez.

Pour les problèmes de références croisées, je suggère de coder par rapport aux interfaces et de les utiliser comme référence dans une autre implémentation plutôt que 2 implémentations se connaissant.

En ce qui concerne la partie MVVM, vous pourriez examiner DSharp qui a une première version d'un port Caliburn Micro pour Delphi. C'est un stade très précoce et peu documenté, mais vous pourriez avoir des idées sur la façon de réaliser MVVM dans Delphi en utilisant une interface graphique et une logique métier faiblement couplées connectées à des liaisons de données. Le magazine Blaise Pascal avait deux articles à ce sujet si vous êtes plus intéressé.

PS Je suppose que vous voulez dire que vous utilisez XE6 car c'est la dernière version.

Stefan Glienke
la source