状況
今晩、私はStackOverflowに関する質問に回答しました。
質問:
既存のオブジェクトの編集は、リポジトリレイヤーまたはサービスで行う必要がありますか?
たとえば、借金のあるユーザーがいる場合。彼の借金を変えたい。UserRepositoryで実行するか、たとえば、BingingServiceなどのサービスでオブジェクトを取得して編集し、保存する必要がありますか?
私の答え:
オブジェクトを同じオブジェクトに変更する責任を負い、リポジトリを使用してこのオブジェクトを取得する必要があります。
状況の例:
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
私が受け取ったコメント:
ビジネスロジックは実際にはサービス内にある必要があります。モデルではありません。
インターネットは何と言っていますか?
だから、サービス層を実際に(意識的に)使用したことがないので、これで検索できました。サービスレイヤーパターンと作業単位パターンについて読み始めましたが、これまでのところ、サービスレイヤーを使用する必要があると確信しているとは言えません。
例えば、Annemic Domain Modelのアンチパターンに関するMartin Fowlerの次の記事をご覧ください。
ドメイン空間には名詞にちなんで名前が付けられたオブジェクトがあり、これらのオブジェクトは、真のドメインモデルが持つ豊富な関係と構造に関連付けられています。ビヘイビアーを見ると問題が発生しますが、これらのオブジェクトにはビヘイビアーがほとんどないため、ゲッターとセッターのバッグにすぎないことがわかります。実際、これらのモデルには多くの場合、ドメインオブジェクトにドメインロジックを配置しないという設計ルールが付属しています。代わりに、すべてのドメインロジックをキャプチャするサービスオブジェクトのセットがあります。これらのサービスはドメインモデルの上に存在し、データにドメインモデルを使用します。
(...)ドメインオブジェクトにあるべきロジックは、ドメインロジック-検証、計算、ビジネスルール-好きなものは何でも。
私にとって、これはまさにその状況のように思えました。そのクラス内にまさにそれを行うメソッドを導入することにより、オブジェクトのデータの操作を提唱しました。ただし、これはどちらの方法でも指定する必要があることを認識しており、これらのメソッドの呼び出し方法(リポジトリを使用)に関連している可能性があります。
また、その記事(下記を参照)では、サービスレイヤーは、実際の作業集約型レイヤーよりも、基礎となるモデルに作業を委任するファサードと見なされていると感じました。
アプリケーション層[サービス層の名前]:ソフトウェアが実行することになっているジョブを定義し、表現力豊かなドメインオブジェクトに問題を解決するよう指示します。この層が担当するタスクは、ビジネスにとって意味があるか、他のシステムのアプリケーション層との対話に必要です。この層は薄く保たれます。ビジネスルールや知識は含まれていませんが、タスクを調整し、次のレイヤーのドメインオブジェクトのコラボレーションに作業を委任するだけです。ビジネスの状況を反映する状態はありませんが、ユーザーまたはプログラムのタスクの進捗を反映する状態を持つことができます。
サービスインターフェイス。サービスは、すべての着信メッセージが送信されるサービスインターフェイスを公開します。サービスインターフェイスは、アプリケーションに実装されたビジネスロジック(通常、ビジネスレイヤーのロジック)を潜在的な消費者に公開するファサードと考えることができます。
そしてここに:
サービスレイヤーには、アプリケーションやビジネスロジックを含めず、主にいくつかの懸念事項に焦点を当てる必要があります。ビジネスレイヤーコールをラップし、クライアントが理解できる共通言語でドメインを翻訳し、サーバーと要求クライアント間の通信媒体を処理する必要があります。
これは、サービスレイヤーについて説明する他のリソースとは大きく異なります。
サービス層は、同じトランザクションに属するアクションの作業単位であるメソッドを持つクラスで構成する必要があります。
または、すでにリンクしている質問に対する2番目の回答:
ある時点で、アプリケーションにはビジネスロジックが必要になります。また、入力を検証して、要求されている悪意のあるものやパフォーマンスの悪いものがないことを確認することもできます。このロジックはサービス層に属します。
"解決"?
この回答のガイドラインに従って、サービスレイヤーを使用する次のアプローチを思いつきました。
class UserController : Controller {
private UserService _userService;
public UserController(UserService userService){
_userService = userService;
}
public ActionResult MakeHimPay(string username, int amount) {
_userService.MakeHimPay(username, amount);
return RedirectToAction("ShowUserOverview");
}
public ActionResult ShowUserOverview() {
return View();
}
}
class UserService {
private IUserRepository _userRepository;
public UserService(IUserRepository userRepository) {
_userRepository = userRepository;
}
public void MakeHimPay(username, amount) {
_userRepository.GetUserByName(username).makePayment(amount);
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
結論
ここではすべてがあまり変わっていません。コントローラーからのコードはサービス層に移動しました(これは良いことなので、このアプローチには利点があります)。しかし、これは私の元の答えとは何の関係もなかったようです。
設計パターンはガイドラインであり、可能な限り実装されるべき規則ではありません。しかし、サービスレイヤーの明確な説明と、それをどのように考慮する必要があるかについてはわかりません。
単純にコントローラーからロジックを抽出し、代わりにサービス内に配置する手段ですか?
コントローラーとドメイン間で契約を結ぶことになっていますか?
ドメインとサービスレイヤーの間にレイヤーが必要ですか?
そして、最後になりましたが、元のコメントに続いて
ビジネスロジックは実際にはサービス内にある必要があります。モデルではありません。
これは正しいです?
- モデルではなくサービスにビジネスロジックを導入するにはどうすればよいですか?