2

はい、Web アプリケーションの MVC アーキテクチャにおける責任の分離に関する別の質問ですが、これには微妙な違いがあると思います...

私の既存の実装は次のようになります。

  • コントローラー: 非常に「薄い」; モデルとビュー、ルーティングとプレゼンテーション ロジックのみの呼び出しを除く
  • モデル: 非常に「厚い」。すべてのビジネス ロジック
  • ビュー: 非常に「薄い」。コンテンツとマークアップは別として、コードはループとデータのフォーマットに限定されます

さらに、このプロジェクトでは、ORM をデータベースの上の抽象化レイヤーとして利用し、「コネクタ」を外部サービスへのラッパー クラスとして利用しています。

私の質問は、モデル間の責任の分離に関するものです。ほとんどの場合、モデルはシステム内の「もの」 (「ユーザー」、「製品」、「注文」など) を模倣しています。

これは、単純なデータ取得要求を処理するのに非常にうまく機能することがわかりました-コントローラーは適切なモデルをインスタンス化し、関連する「ゲッター」を呼び出します。

この問題は、「PlaceOrder」や「RegisterUser」などのより複雑なプロセスが開始されたときに発生します。これらのプロセスは、単一のモデル内で実装できる場合もあれば、実装するためにモデル間の通信または調整が必要な場合もあります。

現状では、これらのケースでは、プロセスがコントローラーによって管理されるのではなく、モデル同士が直接通信します。プロセスをモデル内に保持することは適切なようです (たとえば、「RegisterUser」のビジネス ルールでは確認メールの送信が必要であることをコントローラが認識する必要はありません)。

この実装で私が見つけたのは、私がやや懸念する2つの問題です。

  1. モデルは他のモデルについてあまりにも多くのことを知っているように見えることがよくあります - この実装では、モデルが密結合しすぎているように見えます。
  2. モデル内のメソッドには 2 つの一般的なタイプがあります。「ゲッター/セッター」と、プロセスを管理するメソッドである「プロセス メソッド」の呼び出しに使用したもので、必要に応じてモデルまたは他のモデル内の他のメソッドを呼び出します。これらのメソッドは「より良い説明がないため、モデルのようではありません。

2 種類のモデルを実装するのが適切でしょうか?「データ/オブジェクト モデル」(主に「ゲッター/セッター」とおそらく単純な「プロセス メソッド」で構成され、内部のみで構成され、「プロセス モデル」(「プロセス メソッド」で構成され、複数の(「データ/オブジェクト」)モデルのコラボレーションが必要ですか?

この実装では、「ユーザー」、「製品」、「注文」、および「登録」、「注文」などを表すモデルがあります。

考え?

4

3 に答える 3

1

この問題の解決策は、別のレイヤー、つまりモデルの上に薄いレイヤーを作成することです。この層は、サービス層またはアプリケーション層と呼ばれることもあります。このレイヤーは状態をあまり処理しません。むしろ、さまざまなモデル メソッドとデータ アクセス メソッドを呼び出します。

たとえば、注文を管理するためのサービス クラスが 1 つあるとします。

class OrderService {

placeOrder(Order order) {
   order.doModelStuff();
   orderDao.save(order);

}

removeOrder(order){
    order.cancel();
    orderDao.delete(order);

...
}

また

class UserService {

registerUser(User user) {
    if(userDao.userExists(user)) {
       throw exception: user exists;
    } 
    user.doRegistrationStuff();
    userDao.save(user);
}

サービス層のメソッドは、単一のエンティティを操作することに限定されていません。一般に、複数のモデルにアクセスして操作できます。例えば、

placeOrder(Customer customer, Order order) {
     customer.placeOrder(order);
     save customer, if necessary.
     save order, if necessary
     customer.sendEmail();
     Shipper shipper = new shipper;
     shipper.ship(order, customer.getAddress());
     ...

}

このレイヤーの考え方は、そのメソッドが作業単位を実行することです (通常、単一のユース ケースに対応します)。実際、これはより手続き的な性質です。このレイヤーの詳細については、Martin Fowler などから読むことができます。

注:私のポイントは、サービス/アプリケーション層が何であるかを示すことであり、注文、顧客などの実装を示すことではありません.

于 2012-11-29T16:52:45.413 に答える
0

設計パターンの用語では、モデル オブジェクトを単純なオブジェクト (getter と setter を使用) とプロセス オブジェクト (プロセス ロジックを使用) に分離すると、ドメイン モデルがトランザクション スクリプトを使用した Anemic Domain Model になります。

あなたはそれをしたくありません。モデルオブジェクトがお互いに物事を行うように指示すること(プロセスメソッド)は良いことです。このような結合は、ゲッターとセッターを使用して得られる結合よりも望ましいものです。

オブジェクトは互いに相互作用する必要があるため、ある程度の結合が必要です。外部に公開することを意図したメソッド (そうするならオブジェクトの API) への結合を制限すると、副作用なしでオブジェクトの実装を変更できます。

実装の詳細を公開すると (ゲッターとセッターは実装固有のオブジェクト内部を公開します)、副作用なしに実装を変更することはできません。それは悪い結合です。より完全な説明については、ゲッターとセッターは悪を参照してください。

プロセス メソッドと過度の結合に戻りますが、モデル オブジェクト間の結合を減らす方法があります。何が合理的で、何が危険信号であるべきかについてのガイドラインについては、デメテルの法則を確認してください。

結合を減らすためのパターンについては、ドメイン駆動設計も参照してください。集約ルートのようなものは、結合と複雑さを軽減できます。

tl;dr バージョン: データとメソッドを分離せず、データを隠し、API のみを公開します。

于 2012-11-29T17:21:27.753 に答える
0

Martin Fowler は、著書「Refactoring」の中で、データとアクセサーだけで構成される「データ」モデルは、別のクラスにリファクタリングするのに適しているという意見を持っているようです。彼は、コード内の「悪臭」のライブラリでそれを「データ クラス」と呼んでいます。

これは、異なるプロセス間の相互作用を単純化することを検討する方が良いかもしれないことを示唆していますが、プロセスをそれ自体のデータに密接に結合できるようにします

たとえば、PlaceOrder と OrderData は密接に結合できますが、PlaceOrder には AddOrderToCustomerRecord などの Customer プロセスとの最小限の対話が含まれます。

于 2012-11-29T16:46:47.570 に答える