私がよく避けるデザインパターン:リポジトリパターン

デザインパターンは、ソフトウェア設計で直面する現実の問題に対する実証済みのソリューションを提供します。リポジトリパターンは、アプリケーションのビジネスロジックとデータアクセス層を分離するために使用されます。

データアクセス層には通常、データストレージとの間でデータを操作するためのストレージ固有のコードとメソッドが含まれています。リポジトリが抽象化するデータアクセス層は、ORM(つまり、Entity FrameworkまたはNHibernate)、XMLファイル、Webサービスなどです。SQLステートメントのコレクションでもかまいません。

リポジトリデザインパターンを使用する場合、アプリケーションのビジネスロジック層は、データの永続性がどのように発生するかについての知識を持っている必要はありません。基本的に、リポジトリは、アプリケーションのドメインとデータマッピングレイヤーの間を仲介します。これは、データが実際にデータストレージレイヤーに永続化される方法に関するカプセル化を提供することになっています。

リポジトリパターンは、多くのエンティティがあり、それらのエンティティを操作するための多くの複雑なクエリがある場合に役立つことがあります。この場合の抽象化の追加レイヤーは、クエリロジックの重複を排除するのに役立ちます。

汎用リポジトリ

ジェネリックリポジトリは、CRUD操作を実行するためのジェネリックメソッドのセットで構成されるタイプです。ただし、これは単なるアンチパターンであり、データアクセス層への呼び出しを抽象化するためにEntityFrameworkで頻繁に使用されます。私の意見では、ジェネリックリポジトリを使用することは一般化が行き過ぎです。汎用リポジトリを使用してEntityFrameworkへの呼び出しを抽象化することはお勧めできません。

これを例を挙げて説明しましょう。

次のコードリストは、一般的なリポジトリを示しています。これには、基本的なCRUD操作を実行するための一般的なメソッドが含まれています。

public interface IRepository

   {

       IEnumerable GetAll();

       T GetByID(int id);

       void Add(T item);

       void Update(T item);

       void Delete(T item);

   }

特定のリポジトリを作成するには、以下のコードリストに示すように汎用インターフェイスを実装する必要があります。

public class AuthorRepository : IRepository

   {

       //Implemented methods of the IRepository interface

   }

ご覧のとおり、特定のリポジトリクラスを作成するには、汎用リポジトリインターフェイスの各メソッドを実装する必要があります。このアプローチの主な欠点は、エンティティごとに新しいリポジトリを作成する必要があることです。

このアプローチのもう1つの欠点は次のとおりです。リポジトリパターンの基本的な目的は、データアクセス層によってデータが実際に永続化される方法からドメイン層を分離することです。これが、作成したリポジトリクラスの更新バージョンです。

public class AuthorRepository : IRepository

   {

       private AuthorContext dbContext;

       //Methods of the IRepository interface

   }

前に示したコードリストでわかるように、AuthorRepositoryは、対象のCRUD操作を実行するためにAuthorContextインスタンスを必要とします。では、デカップリングはどこにあるのでしょうか。理想的には、ドメイン層は永続性ロジックの知識を持っていないはずです。

抽象化の追加レイヤー

アプリケーションのドメインモデルと永続性モデルには、明らかに異なる責任があります。前者は動作をモデル化します。つまり、実際の問題とそれらの問題の解決策をモデル化しますが、後者はアプリケーションのデータが実際にデータストアに格納される方法をモデル化するために使用されます。

リポジトリパターンの目的は、永続化ロジックを抽象化し、データの永続化方法の内部実装を非表示にすることです。リポジトリの操作は、十分に表現力があり、一般的ではない必要があります。一般的なリポジトリと、どのシナリオにも適合する操作を含むことができるリポジトリを作成することはできません。これは不要な抽象化になるため、汎用リポジトリパターンはアンチパターンになります。すべてのドメインオブジェクトを同じ方法でモデル化できます。ジェネリックリポジトリは意味のあるコントラクトを定義しません。ジェネリックリポジトリを拡張し、その特定のエンティティにとって意味のある特定の操作セットを提供する特定のリポジトリが再び必要になります。

かなりの数の成熟したデータ永続化テクノロジー(NHibernate、Entity Frameworkなど)が存在するので、なぜこの追加の抽象化レイヤーが必要なのですか?今日利用可能な成熟したORMテクノロジーのほとんどは、同じ機能を備えています。リポジトリを使おうとすると、理由もなく抽象化レイヤーを追加するだけです。例として、AuthorRepositoryに次のようなメソッドが必要になる場合があります。

FindAuthorById()

FindAuthorByCountry()

メソッドと複雑な検索が増えるにつれて、これはさらに悪化します。最終的には、その下で使用されている永続ストレージレイヤーと密接にマッピングされるリポジトリができあがります。