Dovrebbe utilizzare il caso / l'interprete "esegui" il metodo accetta i parametri

8

Nella maggior parte degli esempi di architettura pulita (per lo più progetti Android, però) ho notato che le classi use-case / interactor (unità che incapsulano una caratteristica) spesso condividono la classe base / l'interfaccia, come qui o qui . Altri no ( come qui o here ), permettendo invece agli interpreti di accettare alcuni parametri che vengono poi utilizzati per eseguire alcune logiche.

L'uno o l'altro si avvicina meglio dell'altro? Sono particolarmente interessato a come gli handle di approccio senza parametri usano i casi per qualcosa che richiede l'input dell'utente, ad esempio: diciamo che vogliamo consentire all'utente di modificare un'entità e passarla al server. Potremmo iniettare la stessa entità in use case e chiunque la invochi, ma dovrebbe essere mutabile, in modo che i cambiamenti si riflettano in entrambi i punti. Ma poi non possiamo creare modelli immutabili, che potremmo non volere (a causa di problemi di threading ecc.). Come gestire questo caso?

Scusatemi se uso i termini usecase / interactor in modo errato, ma questo è il modo in cui vengono utilizzati su Android Land, il che potrebbe essere un po 'indietro sui pattern di design

    
posta wasyl 26.05.2016 - 22:42
fonte

1 risposta

6

Consentitemi di ripetere ciò che state dicendo per essere sicuri di essere sulla stessa pagina.

In clean architecture

CasoA

use-case/interactorclassesoftensharebaseclass/interface,likehere

  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();
    }
  }
}

and here

package cat.ppicas.framework.task;

public interface Task<R, E extends Exception> {

    TaskResult<R, E> execute();

}

Caso B

Others do not, and instead allow interactors to accept some parameters that are then used to execute some logic.

like here

package pl.charmas.shoppinglist.domain.usecase;

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

or here

AbstractInteractor.java
GetMarvelCharactersLimit.java
GetMarvelCharactersLimitImp.java
GetMarvelCharactersPaginated.java
GetMarvelCharactersPaginatedImp.java

stop

Hanno entrambi ragione.

La condivisione di un'interfaccia o di una classe base è parte dell'ereditarietà.

Accettare i parametri in modo da poter eseguire la logica attraverso di essi fa parte della composizione.

Is either of these approach better than the other?

Entrambi sono migliori di ciò in cui sono bravi. Sebbene un principio di design popolare affermi, "favorisce la composizione sull'ereditarietà" .

Se capisco, stai vedendo in che modo la composizione e l'ereditarietà possono consentire il polimorfismo e ora che l'hai visto, stai lottando per scegliere tra di loro. Dicendo questo nel linguaggio del pattern: puoi usare il modello di modello o il modello di strategia per ottenere il polimorfismo.

L'ereditarietà ti dà il polimorfismo da solo. Quindi, meno digitando sulla tastiera. Composizione richiede l'aggiunta di delega per esporre e connettere l'interfaccia al parametro. Ciò significa più tipizzazione. Ma la composizione non è vincolata staticamente, quindi è molto flessibile e controllabile.

Should use case/interactor execute method accept parameters?

Ricorda che questo metodo x.y() e questa funzione y(x) sono essenzialmente gli stessi. Un metodo execute() ottiene sempre almeno un parametro.

I'm particularly interested in how parameterless approach handles use cases for something that requires user input for example - say we want to let user edit an entity and pass it to the server. We could inject the same entity into use case and whomever invokes it, but then it would have to be mutable, so that changes are reflected in both places. But then we can't create immutable models, which we may not want (because of threading issues etc). How to handle such case?

Bene, ora stiamo parlando di entità, non di casi d'uso, né di polimorfismo.

Un'entità ha un ID. È molto bello rendere un'entità immutabile. Perché vuoi che un utente modifichi qualcosa di immutabile? Perché vuoi che le informazioni siano esistenti in due posti? Se sì, quale posto conosce meglio?

No, è meglio consentire all'utente di creare qualcosa di nuovo. Se deve avere un ID allora ottiene un nuovo ID univoco. In caso contrario, è un oggetto valore. Se c'è qualcos'altro con un ID preesistente a cui questa informazione deve essere associata, quindi creare una nuova associazione. Non andare a frugare in entità immutabili.

È del tutto possibile modellare un mondo che cambia senza mai aggiornare le tue entità, a patto che tu abbia lo spazio per continuare a creare cose che rappresentano le novità.

    
risposta data 31.05.2016 - 12:11
fonte

Leggi altre domande sui tag