web-dev-qa-db-ja.com

Delphi PascalにMVVMとMVCを実装するためのベストプラクティス

私はDelphi Pascalプログラマーで、最新のEmbarcadero delphi XEを使用しています。モデルビューコントローラーやモデルビュービューモデルなどのデザインパターンを利用したいと思います。

ただし、Pascalでこれを行うためのベストプラクティスについては、Webにはあまり多くありません。私が見つけることができるほとんどの例はC#にあり、一部の言語機能はPascalにはありません。つまり、これらの機能を実装する方法を見つける必要があるかもしれません。

私はこの記事のコードを適応させようとしています here

私が直面している問題をリストします

  • null許容型

PascalにはC#のようにnull許容型がないため、独自に作成しました。

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;
  • プロパティの取得/設定

Null可能な型ができたので、null可能なプロパティを作成できますが、コードの匂いがいくつかあります

たとえば私が作成した場合

    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;

少し厄介です。これについて私にできることは何もないかもしれません。

  • 循環参照

クラスを異なるユニットに分けるのが好きです。

つまり: structure

ユーザーインターフェイスを制御ロジック、モデルおよびデータロジックレイヤーから分離します。

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;

2つのクラスが互いに含まれているため、このコードは壊れています。これはPascalでは実行できません。これはC#ではそのような問題ではありません。考えられる解決策:1.両方のクラスを同じユニットに含めます。ただし、これが設計に適さないと思われる場合は問題です。 2. Bの別の親インターフェースを作成し、そこからBを継承すると、これが回避されます。これはそのような単純なタスクには厄介ですが。

  • 静的クラス

Delphiには静的クラスはありません。これらはコントロールクラスに役立ちます。

  • Delphiで使用するのに最適なコンテナクラス

私は現在Generics.CollectionsでTListとTObjectListを使用しています。これらはDelphi XEで導入されました。delphi7には適切なオプションがないようだったので、これらが使用するのに最適であることを願っています。

私はまだイベントハンドラーとそこで発生する可能性のある問題について考えています。おそらく、まだ考えていない他の問題があるかもしれません。

アドバイスありがとうございます。

10
sav

Spring4Dには、null許容型(演算子のオーバーロードを少し追加したものと同様の実装)とRTLよりも強力なコレクション型が含まれているため、調べてください。それらはまた、特にそれらを渡すときに寿命管理について心配する必要がないので非常に便利なインターフェースベースです。

相互参照の問題については、インターフェースに対するコーディングを提案し、2つの実装がお互いを認識しているのではなく、これらを参照として別の実装で使用することをお勧めします。

MVVMの部分については、Delphi用のCaliburn Microポートの最初のバージョンがあるDSharpを調べてみてください。これは非常に初期の段階であり、ほとんど文書化されていませんが、データバインディングに接続された疎結合GUIとビジネスロジックを使用してDelphiでMVVMを実現する方法についていくつかのアイデアを得るかもしれません。 Blaise Pascal誌には、興味があれば2つの記事が掲載されています。

追伸XE6を使用しているのではないでしょうか。それが最新バージョンです。

9
Stefan Glienke