web-dev-qa-db-ja.com

リポジトリパターン-なぜインターフェースが必要なのですか?

私はインターネットから読んだことがありましたが、インターフェースはこれに使用されています

  • TDDメソッドを使用する
  • 永続化エンジンを置き換える

しかし、インターフェイスがこの時点でどのように役立つかを理解できませんReplace persistance engineEmployeeRepositoryの基本的な(ジェネリックなしの)リポジトリを作成しているとしましょう

public class EmployeeRepository
{
  public employee[] GetAll()
  {
     //here I'll return from dbContext or ObjectContex class
  }
}

では、どのようにインターフェースが登場するのでしょうか?

そして、私がインターフェースを作成したとしたら、なぜアップキャストが使われるのですか?例えば

 IEmployee emp = new EmployeeRepository() ;
 vs
 EmployeeRepository emp = new EmployeeRepository();

リポジトリパターンに関して、インターフェイスのその他の有用性を正確に説明してください。

40
Meson

では、インターフェイスはどのように考えられるのでしょうか。

このような:

public interface IEmployeeRepository
{
    Employee[] GetAll();
}

そして、あなたは好きなだけ多くの実装を持つことができます:

public class EmployeeRepositoryEF: IEmployeeRepository
{
    public Employee[] GetAll()
    {
        //here you will return employees after querying your EF DbContext
    }
}

public class EmployeeRepositoryXML: IEmployeeRepository
{
    public Employee[] GetAll()
    {
        //here you will return employees after querying an XML file
    }
}

public class EmployeeRepositoryWCF: IEmployeeRepository
{
    public Employee[] GetAll()
    {
        //here you will return employees after querying some remote WCF service
    }
}

and so on ... you could have as many implementation as you like

ご覧のとおり、リポジトリの実装方法はそれほど重要ではありません。重要なのは、すべてのリポジトリと実装が定義されたコントラクト(インターフェース)を尊重し、すべてのGetAllメソッドが従業員のリストを返すことです。

そして、あなたはこのインターフェースを使用するコントローラーを持っています。

public class EmployeesController: Controller
{
    private readonly IEmployeeRepository _repository;
    public EmployeesController(IEmployeeRepository repository)
    {
        _repository = repository;
    }

    public ActionResult Index()
    {
        var employees = _repository.GetAll();
        return View(employees);
    }   
}

コントローラーがリポジトリーの特定の実装に依存しなくなったことを確認してください。知っておく必要があるのは、この実装が契約を尊重することだけです。あとは、お気に入りの依存関係注入フレームワークを構成して、希望する実装を使用するだけです。

Ninjectでこれを行う方法の例を次に示します。

  1. インストール Ninject.MVC NuGet
  2. 生成された~/App_Start/NinjectWebCommon.cs 1行のコードでEF実装を使用することを決定したコード:

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IEmployeeRepository>().To<EmployeeRepositoryEF>();
    }        
    

これにより、これらのリポジトリクラスの手動によるインスタンス化を行う必要がなくなり、アップキャストなどについて心配する必要がなくなります。それらを管理するのは依存関係注入フレームワークであり、定義された実装をコントローラーコンストラクターに注入します。

また、この構成を変更するだけで、コントローラーの1行のコードに触れることなく、データアクセステクノロジを切り替えることができます。これが、単体テストの単体テストでも機能します。コントローラーコードがリポジトリに弱く結合されているため(導入したインターフェイスのおかげ)、単体テストで行う必要があるのは、リポジトリで動作を定義できるモック実装を提供することだけです。これにより、データベースなどに依存することなく、インデックスコントローラアクションを単体テストすることができます。完全な分離。

ASP.NET MVCのTDDとDIについて 次の記事 をチェックアウトすることもお勧めします。

79
Darin Dimitrov

リポジトリをインターフェースとして公開します。

public interface IEmployeeRepository
{
    List<Employee> GetAll();
}

これにより、デフォルトのインターフェースなど、インターフェースのさまざまな実装を使用できるようになります。

public class EmployeeRepository : IEmployeeRepository
{
    public List<Employee> GetAll()
    {
        // Return from db.
    }
}

またはテストのもの:

public class TestEmployeeRepository : IEmployeeRepository
{
    public List<Employee> GetAll()
    {
        // Stub some dummy data.
    }
}

リポジトリを使用するコードは、インターフェースの使用にのみ関心があります。

IEmployeeRepository myRepo = MyRepositoryFactory.Get<IEmployeeRepository>();

秘密のソースは、ファクトリー、またはインターフェースを使用可能なタイプに解決するための別のメカニズムです(Ninjectなどの依存性注入フレームワーク、またはCastle Windsorがこの役割を果たします)。

重要なのは使用するコードは実装を気にしないcontractのみです(インターフェース)。これにより、テスト目的で実装を非常に簡単に交換でき、疎結合を促進できます。

明確にするために、インターフェースの使用とリポジトリー・パターンの間には具体的なリンクはありません。それは、インターフェースを使用できる別のパターンにすぎません。

14