web-dev-qa-db-ja.com

ケース/インタラクターの「実行」メソッドを使用してパラメーターを受け入れる必要があります

クリーンなアーキテクチャのほとんどの例では(Androidプロジェクトがほとんどですが)、ユースケース/インタラクタークラス(機能をカプセル化するユニット)に気づきました here または here のように、基本クラス/インターフェースを共有することがよくあります。他のものはしない( ここのように または ここ )。代わりに、インタラクターがいくつかのパラメーターを受け入れることを許可し、その後、いくつかのロジックを実行するために使用されます。

これらのアプローチのどちらかが他方よりも優れていますか?たとえば、ユーザー入力を必要とする何かのユースケースをパラメーターなしのアプローチで処理する方法に特に興味があります。たとえば、ユーザーがエンティティを編集してサーバーに渡せるようにしたいとします。同じエンティティをユースケースとそれを呼び出す人に注入することもできますが、その場合は変更可能である必要があるため、変更は両方の場所に反映されます。ただし、不必要なモデルを作成することはできません(スレッドの問題などが原因で)。そのような場合の対処方法は?

ユースケース/インタラクターという用語を誤って使用した場合はご容赦ください。ただし、これはAndroid土地で使用されている方法であり、設計パターンでは明らかに遅れている可能性があります。

8
wasyl

私たちが同じページにいることを確認するために、あなたの言っていることを繰り返します。

クリーンなアーキテクチャで

enter image description here

ケースA

here のように、ユースケース/インタラクタークラスは多くの場合、基本クラス/インターフェースを共有します。

_  public abstract class UseCase {

  private final ThreadExecutor threadExecutor;
  private final PostExecutionThread postExecutionThread;

  private Subscription subscription = Subscriptions.empty();

  protected UseCase(ThreadExecutor threadExecutor,
      PostExecutionThread postExecutionThread) {
    this.threadExecutor = threadExecutor;
    this.postExecutionThread = postExecutionThread;
  }

  /**
   * Builds an {@link rx.Observable} which will be used when executing the current {@link UseCase}.
   */
  protected abstract Observable buildUseCaseObservable();

  /**
   * Executes the current use case.
   *
   * @param UseCaseSubscriber The guy who will be listen to the observable build
   * with {@link #buildUseCaseObservable()}.
   */
  @SuppressWarnings("unchecked")
  public void execute(Subscriber UseCaseSubscriber) {
    this.subscription = this.buildUseCaseObservable()
        .subscribeOn(Schedulers.from(threadExecutor))
        .observeOn(postExecutionThread.getScheduler())
        .subscribe(UseCaseSubscriber);
  }

  /**
   * Unsubscribes from current {@link rx.Subscription}.
   */
  public void unsubscribe() {
    if (!subscription.isUnsubscribed()) {
      subscription.unsubscribe();
    }
  }
}
_

および ここ

_package cat.ppicas.framework.task;

public interface Task<R, E extends Exception> {

    TaskResult<R, E> execute();

}
_

ケースB

他のものはそうではなく、代わりにインタラクターがいくつかのパラメーターを受け入れることを許可し、その後、いくつかのロジックを実行するために使用されます。

のように ここ

_package pl.charmas.shoppinglist.domain.usecase;

public interface UseCase<Result, Argument> {
  Result execute(Argument arg) throws Exception;
}
_

または ここ

AbstractInteractor.Java
GetMarvelCharactersLimit.Java
GetMarvelCharactersLimitImp.Java
GetMarvelCharactersPaginated.Java
GetMarvelCharactersPaginatedImp.Java

やめる

どちらも正しいです。

インターフェースまたは基本クラスの共有は継承の一部です。

パラメータを介してロジックを実行できるようにパラメータを受け入れることは、構成の一部です。

これらのアプローチのどちらかが他方よりも優れていますか?

どちらも得意分野が優れています。ポピュラーなデザイン原則は述べていますが、 "継承よりも構成を優先する" です。

私が理解しているのであれば、構成と継承の両方がどのようにしてポリモーフィズムを可能にするのかを理解していると思います。これをパターン言語で言うと、テンプレートパターンまたは戦略パターンを使用してポリモーフィズムを取得できます。

継承は、それ自体でポリモーフィズムを提供します。したがって、キーボードでの入力が少なくなります。構成では、委任を追加してインターフェースを公開し、パラメーターに接続する必要があります。それはより多くのタイピングを意味します。しかし、コンポジションは静的にバインドされていないため、非常に柔軟でテスト可能です。

ケース/インタラクターexecuteメソッドを使用してパラメーターを受け入れる必要がありますか?

このメソッドx.y()とこの関数y(x)は基本的に同じであることに注意してください。 execute()メソッドは常に少なくとも1つのパラメータを取得しています。

たとえば、ユーザー入力を必要とする何かのユースケースをパラメーターなしのアプローチで処理する方法に特に興味があります。たとえば、ユーザーがエンティティを編集してサーバーに渡せるようにしたいとします。同じエンティティをユースケースに挿入し、だれがそれを呼び出すこともできますが、変更可能にする必要があるため、変更が両方の場所に反映されます。ただし、不必要なモデルを作成することはできません(スレッドの問題などが原因で)。そのような場合の対処方法は?

さて、私たちはエンティティについて話しているのであり、ユースケースやポリモーフィズムについてではありません。

エンティティにはIDがあります。エンティティを不変にすることは非常に良いことです。なぜユーザーが不変のものを編集する必要があるのですか?なぜ2つの場所に存在する情報が必要なのですか。もしそうなら、どの場所が一番知っていますか?

いいえ、ユーザーが何か新しいものを作成できるようにした方がいいです。 IDが必要な場合は、新しい一意のIDを取得します。そうでない場合、それは値オブジェクトです。この情報を関連付ける必要がある既存のIDを持つものが他にある場合は、新しい関連付けを作成します。不変のエンティティーをいじり回さないでください。

新しいものを表すものを作成し続けるスペースがある限り、エンティティを更新することなく、変化する世界をモデル化することは完全に可能です。

6
candied_orange