OOP Design Patternsで、RepositoryパターンとService Layerの違いは何ですか?
私はASP.NET MVC 3アプリに取り組んでおり、これらのデザインパターンを理解しようとしていますが、私の脳はちょうどそれを取得していない...まだ!!
リポジトリレイヤーは、データアクセスに対する追加の抽象化レベルを提供します。書く代わりに
var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
データベースから単一のアイテムを取得するには、リポジトリインターフェイスを使用します
public interface IRepository<T>
{
IQueryable<T> List();
bool Create(T item);
bool Delete(int id);
T Get(int id);
bool SaveChanges();
}
Get(id)
を呼び出します。リポジトリ層は、基本的なCRUD操作を公開します。
サービス層は、リポジトリを使用するビジネスロジックを公開します。サンプルサービスは次のようになります。
public interface IUserService
{
User GetByUserName(string userName);
string GetUserNameByEmail(string email);
bool EditBasicUserData(User user);
User GetUserByID(int id);
bool DeleteUser(int id);
IQueryable<User> ListUsers();
bool ChangePassword(string userName, string newPassword);
bool SendPasswordReminder(string userName);
bool RegisterNewUser(RegisterNewUserModel model);
}
リポジトリのList()
メソッドはすべてのユーザーを返しますが、IUserServiceのListUsers()
は1人のみを返し、ユーザーはアクセスできます。
ASP.NET MVC + EF + SQL SERVERでは、次の通信フローがあります。
Views <-Controllers-> Service layer-> Repository layer-> EF-> SQL Server
サービス層->リポジトリ層-> EFこの部分はモデルで動作します。
Views <-Controllers-> Service layerこの部分はビューモデルで動作します。
編集:
/ Orders/ByClient/5のフローの例(特定のクライアントの注文を確認したい):
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService; // injected by IOC container
}
public ActionResult ByClient(int id)
{
var model = _orderService.GetByClient(id);
return View(model);
}
}
これは注文サービスのインターフェースです:
public interface IOrderService
{
OrdersByClientViewModel GetByClient(int id);
}
このインターフェイスはビューモデルを返します。
public class OrdersByClientViewModel
{
CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
IEnumerable<OrderViewModel> Orders { get; set; }
}
これはインターフェースの実装です。モデルクラスとリポジトリを使用して、ビューモデルを作成します。
public class OrderService : IOrderService
{
IRepository<Client> _clientRepository;
public OrderService(IRepository<Client> clientRepository)
{
_clientRepository = clientRepository; //injected
}
public OrdersByClientViewModel GetByClient(int id)
{
return _clientRepository.Get(id).Select(c =>
new OrdersByClientViewModel
{
Cient = new ClientViewModel { ...init with values from c...}
Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}
}
);
}
}
Carnotaurusが言ったように、リポジトリは、ストレージ形式からビジネスオブジェクトへのデータのマッピングを担当します。ストレージとの間でデータを読み書きする方法(削除、更新も)の両方を処理する必要があります。
一方、サービスレイヤーの目的は、ビジネスロジックを1つの場所にカプセル化して、コードの再利用と懸念の分離を促進することです。 Asp.net MVCサイトを構築するときにこれが実際に私にとって通常意味することは、この構造を持っていることです
[Controller]は[Repository(ies)]を呼び出す[Service(s)]を呼び出します
私が有用だとわかった原則の1つは、コントローラーとリポジトリーでロジックを最小限に抑えることです。
コントローラーでは、それは私をドライに保つのに役立つからです。別の場所で同じフィルタリングまたはロジックを使用する必要があることは非常に一般的であり、コントローラーに配置した場合は再利用できません。
リポジトリでは、何か良いものが出てきたらストレージ(またはORM)を交換できるようにしたいからです。リポジトリにロジックがある場合、リポジトリを変更するときにこのロジックを書き換える必要があります。リポジトリがIQueryableのみを返し、サービスがフィルタリングを行う場合、マッピングを置き換えるだけで済みます。
たとえば、最近、Linq-To-SqlリポジトリのいくつかをEF4に置き換えましたが、この原則に忠実であったリポジトリを数分で置き換えることができました。私がいくつかのロジックを持っていた場合、代わりに数時間でした。
受け入れられた答え(そして何百もの時間をかけた)には大きな欠陥があります。コメントでこれを指摘したかったのですが、30のコメントで埋められるので、ここで指摘します。
そのように構築されたエンタープライズアプリケーションを引き継ぎましたが、私の最初の反応はWTH?サービス層のViewModels?何年もの開発が行われたため、コンベンションを変更したくなかったので、ViewModelsを返し続けました。 WPFの使用を開始すると、悪夢に変わりました。私たち(開発者チーム)は常に言っていました:どのViewModelですか?本物(WPF用に作成したもの)またはサービスのものですか? Webアプリケーション用に作成されており、UIでの編集を無効にするIsReadOnlyフラグさえありました。 1つのWordによる重大な重大な欠陥とすべて:ViewModel !!
同じ間違いをする前に、上記の私の話に加えて、いくつかの理由があります。
サービスレイヤーからViewModelを返すことは非常に重要です。それは言っているようなものです:
これらのサービスを使用する場合は、MVVMを使用することをお勧めします。使用する必要があるViewModelは次のとおりです。 痛い!
サービスは、UIのどこかに表示されると仮定しています。 WebサービスやWindowsサービスなどの非UIアプリケーションで使用される場合はどうなりますか?
それは実際のViewModelでもありません。 実際のViewModelには可観測性、コマンドなどがあります。これは、悪い名前のPOCOです。 (名前が重要な理由については、上の私の話を参照してください。)
消費アプリケーションは、プレゼンテーション層(ViewModelsがこの層で使用される)であることがより適切であり、C#をよりよく理解します。 別の痛い!
しないでください!
通常、リポジトリはエンティティにデータを入力するための足場として使用されます-サービス層が出てリクエストを送信します。サービス層の下にリポジトリを配置する可能性があります。
リポジトリ層は、データベースにアクセスするために実装され、データベースのCRUD操作を拡張するのに役立ちます。一方、サービスレイヤーはアプリケーションのビジネスロジックで構成され、リポジトリレイヤーを使用してデータベースに関連する特定のロジックを実装できます。アプリケーションでは、別個のリポジトリレイヤーとサービスレイヤーを用意することをお勧めします。リポジトリとサービスのレイヤーを分離することで、コードをよりモジュール化し、データベースをビジネスロジックから切り離します。