クリーンアーキテクチャユースケースをさせインタラクタ応答/表示を処理するために(DIP以下、注入される)プレゼンタの実際の実装を呼び出すことを示唆しています。ただし、このアーキテクチャを実装し、インタラクターから出力データを返し、コントローラー(アダプター層内)がその処理方法を決定できるようにする人がいます。2番目のソリューションは、インタラクターへの入力ポートと出力ポートを明確に定義していないことに加えて、アプリケーションの責任をアプリケーション層から漏えいさせていますか?
入出力ポート
Clean Architectureの定義、特にコントローラー、ユースケースインタラクター、プレゼンター間の関係を説明する小さなフロー図を考慮すると、「ユースケースの出力ポート」がどうあるべきかを正しく理解しているかどうかはわかりません。
六角形アーキテクチャのようなクリーンアーキテクチャは、プライマリポート(メソッド)とセカンダリポート(アダプタによって実装されるインターフェイス)を区別します。通信フローに従って、「ユースケース入力ポート」がプライマリポート(したがって、単なるメソッド)になり、「ユースケース出力ポート」が実装されるインターフェイスになります。実際のアダプターを取得するコンストラクター引数、インタラクターが使用できるようにします。
コード例
コード例を作成するために、これはコントローラーコードになります。
Presenter presenter = new Presenter();
Repository repository = new Repository();
UseCase useCase = new UseCase(presenter, repository);
useCase->doSomething();
プレゼンターインターフェイス:
// Use Case Output Port
interface Presenter
{
public void present(Data data);
}
最後に、インタラクター自体:
class UseCase
{
private Repository repository;
private Presenter presenter;
public UseCase(Repository repository, Presenter presenter)
{
this.repository = repository;
this.presenter = presenter;
}
// Use Case Input Port
public void doSomething()
{
Data data = this.repository.getData();
this.presenter.present(data);
}
}
プレゼンターを呼び出すインタラクター上
前の解釈は、前述の図自体によって確認されているようです。コントローラと入力ポートの間の関係は、「鋭い」頭の実線矢印で表されます(「関連付け」のUMLコントローラーは「ユースケース」を持ちます)、プレゼンターと出力ポートの間の関係は「白」の頭を持つ実線の矢印で表されます(「継承」のUMLは「実装」の1つではありませんが、おそらくとにかくそれが意味です)。
さらに、この別の質問への回答では、Robert Martinが読み取り要求時にインタラクターがプレゼンターを呼び出すユースケースを正確に説明しています。
マップをクリックすると、placePinControllerが呼び出されます。クリックの場所とその他のコンテキストデータを収集し、placePinRequestデータ構造を構築し、PlacePinInteractorに渡します。PlacePinInteractorはピンの場所を確認し、必要に応じて検証し、ピンを記録するPlaceエンティティを作成し、EditPlaceReponseを構築しますオブジェクトを編集し、プレイスエディタ画面を表示するEditPlacePresenterに渡します。
これをMVCでうまく動作させるために、アプリケーションロジックがアプリケーションレイヤーの外部にリークすることを望まないため、従来はコントローラーに入力されていたアプリケーションロジックをここでインタラクターに移動すると考えることができます。アダプターレイヤーのコントローラーはインタラクターを呼び出すだけで、プロセス内でマイナーデータ形式の変換を行う場合があります。
この層のソフトウェアは、ユースケースやエンティティに最も便利な形式から、データベースやWebなどの外部機関に最も便利な形式にデータを変換するアダプターのセットです。
元の記事から、インターフェイスアダプターについて話します。
データを返すインタラクター上
ただし、このアプローチの問題は、ユースケースがプレゼンテーション自体を処理する必要があることです。Presenter
インターフェースの目的は、いくつかの異なる種類のプレゼンター(GUI、Web、CLIなど)を表すのに十分抽象的であり、実際には単に「出力」を意味することがわかりました。非常によく持っていますが、それでも私はそれに完全に自信がありません。
さて、きれいなアーキテクチャのアプリケーションをWebで見てみると、出力ポートをDTOを返すメソッドとして解釈している人しかいないようです。これは次のようになります。
Repository repository = new Repository();
UseCase useCase = new UseCase(repository);
Data data = useCase.getData();
Presenter presenter = new Presenter();
presenter.present(data);
// I'm omitting the changes to the classes, which are fairly obvious
これは魅力的です。なぜなら、プレゼンテーションを「呼び出し」する責任をユースケースの外に移動しているからです。また、このケースでは、ユースケースはまだ外側のレイヤーについて何も知らないため、依存関係の規則を破っていません。
ただし、ユースケースは、実際のプレゼンテーションが実行されるタイミングを制御しません(たとえば、その時点でロギングなどの追加処理を行ったり、必要に応じて完全に中止したりする場合に便利です)。また、コントローラーがgetData()
メソッド(新しい出力ポート)のみを使用しているため、ユースケースの入力ポートを失ったことに注意してください。さらに、インタラクターに何らかのデータを要求して、実際の処理を行うように指示するのではなく、ここで「伝える、尋ねない」という原則を破っているように見えます。最初の場所。
ポイントへ
では、これら2つの選択肢のいずれかは、クリーンアーキテクチャによるユースケース出力ポートの「正しい」解釈ですか?両方とも実行可能ですか?