Deixe-me reiterar o que você está dizendo para garantir que estamos na mesma página.
Na arquitetura limpa
Caso A
As classes de casos de uso / interator geralmente compartilham a classe / interface base, como aqui
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();
}
}
}
e aqui
package cat.ppicas.framework.task;
public interface Task<R, E extends Exception> {
TaskResult<R, E> execute();
}
Caso B
Outros não, e, em vez disso, permitem que os interatores aceitem alguns parâmetros que são usados para executar alguma lógica.
como aqui
package pl.charmas.shoppinglist.domain.usecase;
public interface UseCase<Result, Argument> {
Result execute(Argument arg) throws Exception;
}
ou aqui
AbstractInteractor.java
GetMarvelCharactersLimit.java
GetMarvelCharactersLimitImp.java
Get MarvelCharactersPaginated.java Get
MarvelCharactersPaginatedImp.java
Pare
Ambos estão certos.
Compartilhar uma interface ou classe base faz parte da herança.
Aceitar parâmetros para que você possa executar a lógica através deles faz parte da composição.
Uma dessas abordagens é melhor que a outra?
Ambos são melhores no que são bons. Embora um princípio de design popular afirme, "favorece a composição sobre a herança" .
Se eu estou entendendo, você está vendo como a composição e a herança podem permitir o polimorfismo e agora que você o viu, está lutando para escolher entre eles. Dizendo isso na linguagem de padrões: você pode usar o padrão de modelo ou o padrão de estratégia para obter polimorfismo.
A herança fornece polimorfismo por si própria. Assim, menos digitação no teclado. A composição requer que você adicione delegação para expor e conectar a interface ao parâmetro. Isso significa mais digitação. Mas a composição não é estaticamente vinculada, por isso é muito flexível e testável.
O execute
método de caso / interator de uso deve aceitar parâmetros?
Lembre-se de que esse método x.y()
e essa função y(x)
são essencialmente os mesmos. Um execute()
método está sempre obtendo pelo menos um parâmetro.
Estou particularmente interessado em como a abordagem sem parâmetros lida com casos de uso para algo que requer entrada do usuário, por exemplo - digamos que queremos permitir que o usuário edite uma entidade e passe-a para o servidor. Poderíamos injetar a mesma entidade no caso de uso e em quem quer que a invoque, mas isso teria que ser mutável, para que as mudanças sejam refletidas nos dois lugares. Mas não podemos criar modelos imutáveis, que talvez não desejemos (por causa de problemas de encadeamento, etc.). Como lidar com esse caso?
Bem, agora estamos falando sobre entidades, não casos de uso, nem polimorfismo.
Uma entidade tem um ID. É muito bom tornar uma entidade imutável. Por que você deseja que um usuário edite algo imutável? Por que você deseja que as informações existam em dois lugares? Em caso afirmativo, qual lugar sabe melhor?
Não, é melhor deixar o usuário criar algo novo. Se precisar ter um ID, ele obterá um novo ID exclusivo. Caso contrário, é um objeto de valor. Se houver algo mais com um ID preexistente ao qual essas informações devem ser associadas, crie uma nova associação. Não fique bisbilhotando em entidades imutáveis.
É inteiramente possível modelar um mundo em mudança sem atualizar suas entidades, desde que você tenha espaço para continuar criando coisas que representam o que há de novo.
method is always getting at least one parameter
- isso é um detalhe técnico. "Oexecute
método deve aceitar mais de um parâmetro", se desejar. E, finalmente, a parte sobre a imutabilidade não resolver o problema, quer, que é "como faço para passar usecase uma nova entidade imutável (que reflete as mudanças do usuário) se o seu método execute não aceita parâmetros?