2012-03-02 10 views
1

私はマイクロローンのデータキャプチャとレポートのための非常に基本的なWindows Formsアプリケーションを持っています。私は、EFを使用したかなり良いエンティティモデルの設計を行ってきましたが、EF経由のデータアクセスとWindowsフォームメソッド内のビジネスロジックを使った初期プロトタイプ作成だけでした。私は今、アプリケーションを少しだけ正式化し、フォーム自体にUIロジックだけを書くことに集中したいと考えています。単一レイヤWindowsフォームアプリケーションにはどのような基本アーキテクチャを使用できますか?

私はここでどのような構造とパターンを使用できますか?私は、私のMVC3プロジェクトのための緩やかなリポジトリパターンとビューモデルの設定を使用することに慣れていますが、数年前から多くのwinformsをやっておらず、確信が持てません。いくつかの最近の読書は、リポジトリが純粋にCRUDを行うべきであることを示唆しています。 MVVMやMVPのフル・デザインまでは行きたくはありませんが、どこに何を入れるのか不思議です。

私にとって最も顕著な構造は、ビジネスロジックと操作を含むように自分のエンティティモデルを拡張することです。 AllocatePaymentメソッドをClientクラスに追加し、クライアントが未払いの融資に対して支払った金額をクライアントに割り当てるなどの処理を行いますが、これはまったく正しいとは限りません。さらに悪いことに、込み合っているLoanManagerタイプのモノリスクラスであり、すべての静的メソッドがあります。

このプロトタイプを、現在の構造のアプリデザインにうまくリファクタリングするにはどうすればよいですか?リファクタリングを開始する前にTDDのアプローチを取り入れたいと思います。これは、私が決定したどのようなクラス構造の低レベルのデザインにも影響を与えるのに役立つようです。

答えて

1

Domain model静的ではなくインスタンスメソッドとして実装されている場合、パターンは非常に良好です。すべてのオブジェクトには、その状態といくつかの特定の動作があります。

これは、ドメインロジックがどこにあるべきかについてです。このようにユニットテストは簡単に書くことができます。何らかの状態でオブジェクトを作成します。メソッドを呼び出し、期待通りかどうかを確認します。

永続化はActiveRecord/Repository/DataMapperで行うことができます ActiveRecordは単発責任の原則に違反しているので、私は本当に好きではありませんが、自分の好みです。 FowlerのEAAのそれぞれのパターンについての素晴らしい議論があります。here

簡単にするために、私はCastleActiveRecordのような既に完成した解決策を使うか、簡単なリポジトリを実装します。 現在のリポジトリにはpostがあります。

ビジネスロジックを含むモデルを作成することもできます。永続性を担うリポジトリ/エンティティを実装します。フォームはあなたのモデルのみを表すべきです。コントローラは、有限の集合しか存在しないため、ユーザアクションを提供することができます。

ちょうどの場合:データバインディングはほとんどのデータをコントロールとゼロコードで関連付けることができるWinFormsの優れた機能です。

あなたのアーキテクチャが満たす必要がある制限がある場合、それぞれ独自の賛否両論があるため、議論のポイントになる可能性があります。しかし、MVCパターンは80年代以来ここにあり、その視聴者はもっと広くなっています:)

0

TDDを簡単にするために、すべてのビジネスロジックをWindowsフォームコードから別のクラスライブラリに分けることをお勧めします。 Windowsフォームコードのテストを記述しないでください。 Winformsプロジェクトをビジネスロジックから解放してください。クラスライブラリはテストで完全に覆われている必要があります。

これは、Winforms以外のインターフェイスを後で書き込むことができるという利点があります。コマンドラインインターフェイスまたはウェブインターフェイス。また、フィニッシュのようなテストツールを使用して、パブリックインターフェイスを介してクラスライブラリをテストすることもできます。

+0

私はすべてのビジネスロジックをクラスライブラリに入れたいと考えていますが、それを行うためのパターンや構造に関する提案を探しています。スケールの最悪の終わりには、すべての静的メソッドを持つ1つの大きなBusLogクラスを持つパブリックインターフェイスを持つことができました。理想主義的な終わりに、私は各エンティティ、コマンドなどのためにいくつかのクラスを持っています。 – ProfK

0

私はWinForms(または実際には問題なく動作する.NET)についてはわかりませんが、私が知っていること(または覚えていると思います)に基づいて提案します。

3つの変数Age、Amount、Hair Colorに基づいてリスクを計算する簡単なフォームクラスがあるとします。 [レート]ボタンをクリックすると、適切な文字列、「高」、「中」、および「低」でラベルが更新されます。

public void btnRate_click() { 
    var RiskScore = 0; 
    if(txtAge.Value < 25) 
    RiskScore += 2; 
    else if(txtAge.Value < 40) 
    RiskScore += 1; 

    if(txtAmount.Value < 2.00) 
    RiskScore += 10; 
    else if(txtAmount.Value < 10.00) 
    RiskScore += 3; 
    else if(txtAmount.Value < 50.00) 
    RiskScore += 5; 

    if(txtHairColor.Value == "Red") 
    RiskScore += 75; 

    if(RiskScore < 2) 
    lblResult.Value = "Low"; 
    else if(RiskScore < 8) 
    lblResult.Value = "Medium"; 
    else 
    lblResult.Value = "High"; 
} 

このコードでは、いくつかのテストをレイアウトする前に、いくつかの簡単な「プリファクタリング」から始めます。私はReSharperのようなIDEが本当に安全であり、望ましくない副作用をほとんど残さないため、自動的に行うことができる標準的なリファクタリングを使用する傾向があります。

最初に行うことは、コード内の重複を削除することです。具体的には、extracting some local variables

public void btnRate_click() { 
    var RiskScore = 0; 
    var Age = txtAge.Value; 
    if(Age < 25) 
    RiskScore += 2; 
    else if(Age < 40) 
    RiskScore += 1; 

    var Amount = txtAmount.Value; 
    if(Amount < 2.00) 
    RiskScore += 10; 
    else if(Amount < 10.00) 
    RiskScore += 3; 
    else if(Amount < 50.00) 
    RiskScore += 5; 

    var HairColor = txtHairColor.Value; 
    if(HairColor == "Red") 
    RiskScore += 75; 

    var Result = "" 
    if(RiskScore < 2) 
    Result = "Low"; 
    else if(RiskScore < 8) 
    Result = "Medium"; 
    else 
    Result = "High"; 

    lblResult.Value = Result; 
} 

このリファクタリングは迅速だったと今は周りの変数宣言を移動し、少しのコードを整理する瞬間を取るよCtrl+Alt+Vを使用して自動的に行うことができます。

public void btnRate_click() { 
    var Age = txtAge.Value; 
    var Amount = txtAmount.Value; 
    var HairColor = txtHairColor.Value; 

    var RiskScore = 0; 
    var Result = "" 

    if(Age < 25) 
    RiskScore += 2; 
    else if(Age < 40) 
    RiskScore += 1; 

    if(Amount < 2.00) 
    RiskScore += 10; 
    else if(Amount < 10.00) 
    RiskScore += 3; 
    else if(Amount < 50.00) 
    RiskScore += 5; 

    if(HairColor == "Red") 
    RiskScore += 75; 

    if(RiskScore < 2) 
    Result = "Low"; 
    else if(RiskScore < 8) 
    Result = "Medium"; 
    else 
    Result = "High"; 

    lblResult.Value = Result; 
} 

これまで達成してきたことは、ビジネスルール(リスク計算)をUIコンポーネント(フォームコントロール)から分離することでした。次のステップは、それらのビジネスルールをUIクラスから外して他の場所に取り出すことです。もう1つのリファクタリングが順調です。このコードを見ると、このメソッドでは4つの変数が操作されています。コードが同じ変数で動作するとき、それはしばしばそこにクラスが潜んでいるというサインです。ここでExtract Method Objectリファクタリングを使用しましょう...(このキーストロークは覚えていませんが、そこにあることは間違いありません)

このブロックの内容を見ると、この新しいクラスはRiskCalculatorと呼ばれます。リファクタリング後のコードは次のようになります。

public void btnRate_click() { 
    var Age = txtAge.Value; 
    var Amount = txtAmount.Value; 
    var HairColor = txtHairColor.Value; 

    var Result = new RiskCalculator(Age, Amount, HairColor).Invoke(); 

    lblResult.Value = Result; 
} 

// In RiskCalculator.cs 
public class RiskCalculator { 
    private int Age; 
    private double Amount; 
    private string HairColor; 

    public RiskCalculator(int Age, double Amount, string HairColor) { 
    this.Age = Age; 
    this.Amount = Amount; 
    this.HairColor = HairColor; 
    } 

    public string Invoke() { 
    var RiskScore = 0; 
    var Result = "" 

    if(Age < 25) 
     RiskScore += 2; 
    else if(Age < 40) 
     RiskScore += 1; 

    if(Amount < 2.00) 
     RiskScore += 10; 
    else if(Amount < 10.00) 
     RiskScore += 3; 
    else if(Amount < 50.00) 
     RiskScore += 5; 

    if(HairColor == "Red") 
     RiskScore += 75; 

    if(RiskScore < 2) 
     Result = "Low"; 
    else if(RiskScore < 8) 
     Result = "Medium"; 
    else 
     Result = "High"; 
    return Result; 
    } 
} 

ここではどこかになっています。 RiskCalculatorにはビジネスロジックのみが含まれており、現在はテスト可能です。次のステップは、電卓の周りにいくつかの単体テストを書いて、すべてのビジネスルールを検証することです。これにより、実際の計算コードをリファクタリングしてクリーンアップすることができます。

テストを書くことによって、RiskCalculatorは本当にこのクラスの良い名前ではないことがわかります。つまり、コンストラクタに渡されているデータが実際にあなたのローンを表していると思います。あなたが現在のRiskCalculatorのテストの良い基盤を持っていることを考えると、いくつかのRenameリファクタリングを実行することができます。 Rename Methodから始めます。

Invokeの方法は実際には名前として有益ではないので、名前を変更します。それは何ですか?私はそれが実際にリスク計算を行っていると言いたいので、それをcalculateRiskとしましょう。その後、リスクをどのように計算しているのかを自問しなければなりません。答えはローンなので、それが2番目のリファクタリングになります。名前変更クラスのリファクタリングを使用し、RiskCalculatorの名前をLoanに変更します。これがシステムの最初のドメインオブジェクトになります。

// RiskCalculator.cs has now become Loan.cs 
public class Loan { 
    // ... 

    public string CalculateRisk() { 
    // ... 
    } 
} 

これらの各リファクタリングの後、テストを実行して、引き続きテストを実行する必要があります。 CalculateRiskメソッドでそのひどいビジネスロジックをクリーンアップすることで、引き続き続行できます。私はおそらくいくつかInline Temporary Variableをすることによって、これをクリーンアップするでしょう

public void btnRate_click() { 
    var Age = txtAge.Value; 
    var Amount = txtAmount.Value; 
    var HairColor = txtHairColor.Value; 

    var Result = new Loan(Age, Amount, HairColor).CalculateRisk(); 

    lblResult.Value = Result; 
} 

と変数のリファクタリングを抽出します。今、私たちのドメインオブジェクトは、我々は次のようになりべき、そのイベントハンドラに戻って私たちの目を向けることができ、クリーンであることを

public void btnRate_click() { 
    var MicroLoan = new Loan(txtAge.Value, txtAmount.Value, txtHairColor.Value); 
    lblResult.Value = MicroLoan.CalculateRisk(); 
} 

今はかなりきれいだし、台無しにそこに多くのコードが実際にそこではありませんので、この時点でのテストの必要性の多くはありません。

希望に役立ちます。私はリポジトリに関するあなたの質問に本当に答えなかったが、これはあなたに始めるための道を与えることを望んでいる。あなたのロジックをどこに置くべきかについては、Single Responsibility Principleを覚えておいてください。それはあなたのリポジトリに何が入っているのか、そうでないのかを決めるのに役立ちます。また、Loanクラスを他の小さく集中したクラスに分割する可能性もあります。

Good Luck! ブランドン

あなたは、この既存の質問を見て持つことができ
1

Windowsフォームの基本モデルでは、UIコントロール内外でデータをバインドすることができます。したがって、コードビハインドは、テスト可能なロジックを配置するのに適していません。

私はこれを(ASP.NET Webフォームでも)行っていますが、いつもModel-View-Presenter (MVP)を使用しています。このパターンは単純であり、可能な限り懸念を分けています。可能であれば、WPFを選択してMVVMを使用します。これは、UIがリバインドを反応的に処理できるようにすることによって、さらに進んでいきます。

これが役に立ちます。

関連する問題