J'essaie de concevoir un cadre asynchrone et je voulais savoir ce que les gens pensent être le pour/le contre du motif de rappel par rapport au motif d'observateur.
Callback pattern:
//example callback
public interface Callback{
public void notify(MethodResult result);
}
//example method
public class Worker{
public void doAsyncWork(Callback callback){
//do work
callback.notify(result);
}
}
//example observer pattern
public interface EventListener{
public void notify(MethodResult result);
}
public class Worker{
private EventListener listener;
public registerEventListener(EventListener listener){
this.listener=listener;
}
public void doAsyncWork(){
//do work
listener.notify(result);
}
}
Je travaille avec un cadre qui semble utiliser ces deux modèles. Le modèle EventListener n'est pas le modèle typique car il ne contient pas de liste des écouteurs. Ceci peut facilement être implémenté en créant un CompositeListener qui a sa propre sémantique sur la priorité des écouteurs et sur la façon de gérer la distribution des événements à chaque auditeur, par exemple création d'un nouveau thread pour chaque écouteur par rapport aux notifications en série. (Je pense en fait que c’est une bonne idée car c’est une bonne séparation des préoccupations et une amélioration du modèle standard observateur/auditeur).
Avez-vous des idées sur le moment d'utilisation de chacun?
Thxs.
Les deux modèles sont excellents et le choix dépend de ce que vous allez construire et de la manière dont votre framework sera utilisé.
Si vous essayez de créer un système de publication-abonnement avec le flux de travail typique suivant:
alors le motif Observer
est un choix naturel pour vous. Lorsque vous utilisez un framework, vous devez également envisager l’utilisation de EventBus pattern pour obtenir un couplage lâche.
Si vous n'avez besoin de rien de plus qu'une simple exécution asynchrone et qu'un flux typique utilisant votre infrastructure est:
ou
alors vous devriez aller avec Callback
simple.
Mais pour obtenir une API plus propre et utilisable, je vous recommanderais de vous débarrasser de l'abstraction Callback
et de concevoir votre code opérateur pour renvoyer une sorte de Future
.
public interface Worker<T> {
Future<T> doAsync();
}
Et Worker
peut être utilisé de la manière suivante:
Future<Integer> future = worker.doAsync();
// some work here
Integer result = future.get(); // waits till async work is done
Future
pourrait être un standard Java Future . Mais je vous suggérerais d'utiliser ListenableFuture
from gava library.
Les modèles de commande, de rappel et d'observateur ont une sémantique différente:
Dans votre exemple, vous pouvez combiner des modèles de rappel et d'observateur pour obtenir une plus grande flexibilité d'API:
Je dirais que le modèle de rappel est meilleur car il est plus simple, ce qui signifie qu'il sera plus prévisible et moins susceptible d'avoir des bogues en raison de son propre état de mutation. Un exemple de ceci en fonctionnement serait la façon dont GWT gère la communication navigateur/serveur .
Vous voudrez peut-être utiliser des génériques:
//example callback
public interface Callback<T> {
public void notify(T result);
}
//example method
public class Worker{
public void doAsyncWork(Callback<SomeTypeOrOther> callback){
//do work
callback.notify(result);
}
}
Les deux modèles partagent peu d'intentions communes excepté,
Le modèle observable peut notifier plusieurs auditeurs. D'autre part, le modèle de commande sera le mieux adapté, où vous avez besoin d'un gestionnaire de rappel unique.
Dans le modèle de commande, il est facile d'implémenter l'opération d'annulation.
À votre santé!