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


10

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

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

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

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

  • 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;

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

  • 循環参照

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

つまり: 構造

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

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には適切なオプションがないように思われるため、これらを使用するのが最善であることを願っています。

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

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


私はもともとコードレビューでこの質問をしましたが、ここに投稿することが提案されました。
sav 2014

回答:


9

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

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

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

PSそれはあなたがXE6を使用していることを意味していると思いますそれが最新バージョンです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.