私はMVCプロジェクトの新しいフェーズに取り組んでいます。最初のフェーズはかなり小さく、それほど複雑ではありませんでした。次のフェーズは非常に複雑で、はるかに大きくなります。最初のフェーズでは、さまざまな理由で徹底的な自動テストを行うというアイデアについて話し合い、破棄しました。
新しいフェーズでは、私たちのチームに自動テストに投資してもらいたいと思います。テストを制御可能にするためにデータベースの作業をスタブ化する必要があるため、依存性注入なしで役立つことは何もできないと思います。
私が苦労しているのは、依存性注入をビジネスレイヤーに後付けすることです。既存のビジネスオブジェクトには状態と動作があり、(静的メソッドを介して)自身のインスタンスをロードする責任があります。たとえば、次のように単純化しすぎた例があります。
public class User
{
public User(string userName)
{}
public bool Authenticate()
{}
public static User GetByUserName(string userName)
{
//Do some DB querying, and then map the data object to a new instance:
UserRepository repository = new UserRepository();
var databaseObject = repository.list(u => u.userName = userName);
User user = new User();
user.userName = databaseObject.userName;
// populate other fields
return user;
}
}
一見すると、次のことが必要になるようです。
- コンストラクターの依存関係としてリポジトリーを挿入します
- GetByUserNameを、Userの静的メソッドではなくなるように変更します
- GetByUserNameメソッドでUserのインスタンスを作成できるように、ある種のファクトリを実行します
これらすべてを合理的な方法で行う方法がわかりません。#1は些細なことですが、#2と#3はそれほど些細なことではありません。これが私が#2を行う方法について考えていることです:
- 構造はほとんどそのままにして、staticキーワードを削除するだけです。つまり、ユーザー名でユーザーを取得するには、Userオブジェクトのインスタンスを作成してから、GetByUserNameメソッドを呼び出す必要があります。これは私の非常に洗練された匂いテストに合格しません。
- ユーザーのロードと保存の責任をある種のUserCollectionオブジェクトに移動します。これは、ほとんどすべてのビジネスオブジェクトが基礎となるコレクションオブジェクトを必要とし、ドメインモデルをより貧血にするため、私には疑わしいようです。
- リポジトリと直接インターフェースします。現在、コントローラーはUser.GetByUserName()を呼び出して、ユーザードメインオブジェクトを取得して作業を行う場合があります。代わりに、コントローラーはリポジトリーを認識し、Repository.list()を呼び出します。それは私には漏れているように思えます-突然、コントローラーはビジネス的なことをしているように感じます。
次に、#3があります。私のオプションは、IOCコンテナを使用してファクトリメソッド(autofacファクトリデリゲートなど)を挿入するか、各オブジェクトのファクトリを手動で作成することのようです。単体テストでautofacを使用するか、各オブジェクトのファクトリデリゲートをスタブ化する必要があるため、autofac方法論を使用するのはリークのようです。ある時点で、IOCコンテナを意識せずにDIを使用できるようにするためだけに、開発者にかなりのワークロードを課しているため、すべてのオブジェクトのファクトリを作成するのは厄介なようです。
私はこれらの主題を検索するためにできることをしましたが、上記の欠点を伴わない具体的な例は実際には多くありません。
「良いデザイン」を失うことなく、または「あまりにも多くの仕事」をすることなく、#2と#3を解決するためのいくつかのテクニックは何ですか?