web-dev-qa-db-ja.com

クリーンアーキテクチャ-内部のドメインレベルのユースケースに向けてリクエストデータを渡す方法

ユースケースインタラクター:

Use Case Interactor

この画像では、リクエストがユースケースインタラクターに到達するまでレイヤーを通過する方法を示しています。

コントローラーはどのようにしてユースケースインタラクターに向けてリクエストを渡しますか?リクエストとは、ユーザーからのデータ(多分フォーム)を意味します

入力ポートがインターフェイスであることを理解していますが、ユースケースインタラクターに向けて入力ポートを介してデータをどのように渡しますか?

また、すべてのユースケースは独自のもの入力ポートを持っていますか?もしそうなら、それはあまり意味がありません、インターフェースで抽象化の層を追加する代わりに、コントローラーの参照としてユースケースを使用しないのはなぜですか。ポイントは何ですか?コントローラーが存在するレイヤーは、ユースケースが配置されているレイヤーを認識しています。これが私が意味することは次のとおりです:
クラスがある場合:AddUserUseCase、そのクラスは独自の入力ポート(インターフェース)を持つ必要がありますか:AddUserInputPort。または、UserInputPortのようなより一般的なものを作成し、すべてのUserUseCasesに実装させることはできますか?

1
NCode

この図は、コンポーネントを構成するさまざまな要素と、レイヤー間のインターフェースの一般的なビューを示しています。インターフェースとは、インターフェースのタイプを意味するものではありません(C#やJavaのように、UMLでは<<interface>>ステレオタイプ)、ただしより一般的な方法でこの用語を使用します-ソフトウェアコンポーネントによって公開されるパブリック(外部から見える)要素のセット(つまり、クラスの場合はパブリックメソッドとプロパティ、またはコンポーネントやレイヤーの「表面レベル」クラスなど)。この図は、プログラムのクラスとしてすべての要素を含める必要がないという意味で一般化されています。あなたは私の意味がすぐにわかります。

コントローラーはどのようにしてユースケースインタラクターに向けてリクエストを渡しますか?

したがって、ユースケースインタラクターの(上記の意味での)インターフェースはtwoもの-入力ポートインターフェースタイプandリクエストモデルデータ構造で構成されます。要求モデルは、入力ポートを通過するインタラクターへの入力です。これはクラスやデータ構造である必要はありません。入力ポートで定義されたメソッドへのパラメーターのリストである可能性もありますが、ここではそれ自体をより一般化した方法で示しています。コントローラー解釈要求(ビューから)、ビジネスロジックとサポートされるユースケースの観点からそれが何を意味するかを理解し、適切なユースケースで適切なメソッドを適切なパラメータ(つまり、パラメータリストまたはリクエストモデル構造のインスタンスのいずれかを構築します)-これは、「リクエスト」(特定のユースケースのコンテキストで再解釈された)が渡される方法です。

ここで、リクエストモデルは概念的にはユースケースによって所有および定義され、そのインターフェース(いわゆる提供されたインターフェース)の一部であり、hasになることに注意してくださいアーキテクチャー境界のその側で、ユースケース層が上位層から独立したままになるようにする(依存関係の方向に関するルール)。レイヤー間の契約では、ユースケースは「ここで、これらのメソッドとこれらのデータ構造を提供し、提供するサービスを使用する必要がある場合に入力として使用する」と言っています。

同様に、出力ポートインターフェイスタイプと応答モデルデータ構造は、拡張ポイントのインターフェイス(いわゆる必須インターフェイス)を形成します。つまり、これは、いくつかの動作を実行してユースケースにプラグインできる場所です。これは、プレゼンターが出力ポートを実装することによって行うことです。これにより、ユースケースはそれが存在することさえ知らずにプレゼンターを呼び出すことができます。これは古典的な依存関係の逆転であり、アーキテクチャの境界を越えた結合の方向を制御します。繰り返しになりますが、応答モデルは個別のデータ構造でも、単なるパラメーターのリストでもかまいません。ユースケースで定義されているコントラクトは、「このインターフェイスを実装することにより、ここにプラグインできます。これらを呼び出して、これらのデータ構造を使用してデータを提供します」です。

現在、混乱の可能性のある1つの点は、実際のアプリケーションでは、通常「OutputPort」や「UseCaseInteractor」などの名前が付いていないことです。これらは、これらの概念を説明するために使用される単なる総称です。ユースケースインタラクターには、わかりやすい名前が付けられます。 「予約」(まあ、モデル化されているドメインのコンテキストで意味があります);出力ポートは "IReservationsObserver"と呼ばれるインターフェースである可能性があり、興味深い変更を観察したいものはすべてそのインターフェースを実装し、それ自体をReservationsオブジェクトに登録します(これは1つの可能性にすぎません。これは原則として使用しないでください-これは例です)オブザーバーパターンに基づいて、頭のてっぺんから)。入力ポートは、予約関連のメソッドを提供する「IReservations」と呼ばれるインターフェースである可能性があります。 「MakeReservation(ReservationRequestDetails details)」のようなものかもしれません。「ReservationRequestDetails」はリクエストモデル(特定のユースケースシナリオのデータモデル)です。

(緑のプレゼンテーションレイヤー)リクエストは、コントローラーのインターフェイスの一部です(概念的にはコントローラーが所有しています)。2。多くの場合、そこに含まれるデータは、ユースケースレイヤーに適した形式ではありません(たとえば、数値は文字列として表される場合や、他のレイヤーでは意味をなさないプレゼンテーション固有のフィールドを含む場合があります)。コントローラはそれを受け取り、それを基礎として使用して、ユースケースへの入力をより直接表現する(赤のユースケース層)要求モデルを構築します。

また、明確にするために、一般的に、すべてのユースケースを処理するユースケースインタラクターは1つだけではありません。また、これまでに見てきたように、ダイアグラムは使用しないでください文字通り;ユースケースインタラクターボックスは1つのクラスを表すことができますが、共同作業を行うクラスの小さなグループの代理になることもあります。同じように、要求モデルと応答モデルは実際に、ユースケースの外部境界でさまざまなメソッドへのパラメーターとして機能するタイプのグループを表すことができます。

また、すべてのユースケースに独自の入力ポートがありますか?もしそうなら、それはあまり意味がありません、インターフェースで抽象化の層を追加する代わりに、コントローラーの参照としてユースケースを使用しないのはなぜですか。ポイントは何ですか?

haveしてはいけません。やりたいことは、レイヤー間の依存関係の方向と数を制御することです。外層は、内層から直接参照するもの(タイプまたはその他の要素のいずれかに依存)1 サービスとして、内部ロジック、パラメータなどのために、それが何らかの方法で使用する内部層から)。これらの参照される型/要素は、「外側の表面」、つまり内側の層の公開されたパブリックインターフェイスを形成します。これらは、変更に対して比較的安定している必要があります。それらに変更を加えると、それらは直接それらに依存するため、外側のレイヤーに伝播します。この「外面」の背後にある内層は効果的にカプセル化されているため、再構成してリファクタリングできます。

これで、提供した画像では、依存関係構造は、プレゼンテーションレイヤーが具体的なユースケースインタラクターの知識を持たないようになっています。つまり、ユースケースレイヤーの内部にあり、さらにいじることができます。または外の部品に影響を与えないでより少し。しかし、あなたはhaveでその正確な依存関係構造を持つことはしません。入力ポートは、インターフェースタイプである必要はありません。具象クラスまたは抽象基本クラスである可能性があります。または、まったく使用しないこともできます。後者の場合、コントローラーはインタラクターに直接依存するため、インタラクターは「表面レベル」タイプの一部になります。次に、内部実装を変更または再編成する場合は、Interactorのパブリック要素を変更しないようにします。変更がより複雑な場合は、おそらくextractサブセットリファクタリング中にそのコードを新しいクラスに変換します。これにより、ダイアグラム上の構造に似た構造になります。ただし、インタラクタが入力ポートなどの役割を担うことになります。

または、UserInputPortなどのより一般的なものを作成してから、すべてのUserUseCaseにそれを実装させることができますか?

ユースケースが特定のことを実行するように設計されたオブジェクトであることを確認してください(特定の使用シナリオをサポートします)。そのため、一般的に、それらのグループの汎用インターフェースを作成することには意味がありません(それはアイデアではありません)。特定の場合にそうする。


1 「その他の要素」は、2つの層の間の「契約」の一部であるものであれば何でもかまいません-特定のデータは特定の構造(タイプとして明示的に定義されていなくても)、ある種の規則などを持っているという期待。

2 この図のView/ViewModel/Controllerの部分は少しあいまいです。そこにある正確な依存構造は、使用するMVC/MVPバリアントによって異なります。たとえば、ビューはコントローラを直接参照する場合があります(それを呼び出してリクエストを渡すため)。かどうか-おそらくコントローラーは、表示されていないイベントキューをポーリングまたはサブスクライブします。 ViewとViewModel間の相互作用は、使用されるフレームワークのデータバインディングメカニズムによってサポートされる場合があります。プレゼンターは、ViewModelや、コントローラーなどとマージできます。

0

すべての建築フレームワークには、独自のビルディングブロックのセットがあります。これは、出発点として役立ちますが、決して固いものではありません。ボブおじさんはクリーンアーキテクチャの 彼の記事 でこれについてさえ言及しています:

これらのアーキテクチャはすべて細部が多少異なりますが、非常に似ています。それらはすべて同じ目的、つまり懸念の分離です。 ...常にこの4つの[円]だけを持たなければならないというルールはありません。ただし、依存関係ルールは常に適用されます。ソースコードの依存関係は常に内側を指します。

ポートとインタラクターは基本的に、UIレイヤーから切り離されたドメインモデル(つまり、依存関係ルール)を持つことになります。ポートは、レイヤー間のコントラクトを定義するという意味ではインターフェースですが、コードでインターフェースを使用する必要はありません。シンプルに保ち、アプリケーションにとって意味のあることをしてください。

2
casablanca