Très typiquement, j'ai une situation où un objet donné devra avoir de nombreux auditeurs. Par exemple, je pourrais avoir
class Elephant {
public void addListener( ElephantListener listener ) { ... }
}
mais j'aurai beaucoup de telles situations. C'est-à-dire que je vais également avoir un objet Tiger
qui aura TigerListener
s. Maintenant, TigerListener
s et ElephantListener
s sont assez différents:
interface TigerListener {
void listenForGrowl( Growl qrowl );
void listenForMeow( Meow meow );
}
tandis que
interface ElephantListener {
void listenForStomp( String location, double intensity );
}
Je trouve que je dois toujours continuer à rééchaler le mécanisme de radiodiffusion dans chaque classe d'animaux, et la mise en œuvre est toujours la même. Y a-t-il un modèle préféré?
Au lieu de chaque Listener
ayant des méthodes spécifiques pour chaque type d'événement que vous pouvez l'envoyer, modifiez l'interface pour accepter une classe générique Event
. Vous pouvez ensuite sous-classes Event
à des sous-types spécifiques si vous avez besoin ou si vous le souhaitez contenir d'état tel que double intensity
.
Tigerlistener et Elephentlistener sont alors devenus
interface TigerListener {
void listen(Event event);
}
En fait, vous pouvez ensuite refacturer davantage cette interface dans une plaine Listener
:
interface Listener {
void listen(Event event);
}
Vos implémentations Listener
peuvent ensuite contenir la logique dont elles ont besoin pour les événements spécifiques qui se soucient de
class TigerListener implements Listener {
@Overrides
void listen(Event event) {
if (event instanceof GrowlEvent) {
//handle growl...
}
else if (event instance of MeowEvent) {
//handle meow
}
//we don't care about any other types of Events
}
}
class ElephentListener {
@Overrides
void listen(Event event) {
if (event instanceof StompEvent) {
StompEvent stomp = (StompEvent) event;
if ("north".equals(stomp.getLocation()) && stomp.getDistance() > 10) {
...
}
}
}
}
La relation clé entre l'abonné et l'éditeur est que l'éditeur peut envoyer des événements aux abonnés, ce n'est pas nécessairement qu'il peut envoyer certains types d'événements - ce type de refactoring pousse cette logique de l'interface dans les implémentations spécifiques dans les implémentations spécifiques. .
Je pense que vous le faites correctement, car vos interfaces ont une valeur sémantique et expriment ce qu'ils écoutent (par exemple, grognements et mières au lieu de piétine). Avec une approche générique, vous pourrez peut-être réutiliser le code de la radiodiffusion, mais vous risquez de perdre la lisibilité.
Par exemple, il y a le Java.beans.PropertyChangeSupport
Qui est un utilitaire permettant d'exécuter des oberservers à écouter des changements de valeur. Il fait la radiodiffusion, mais vous devez toujours mettre en œuvre la méthode de votre classe de domaine et déléguer à l'objet de propriétéChangeSupport. Les méthodes de rappel n'ont-elles pas de sens en eux-mêmes et les événements diffusés sont basés sur des cordes:
public interface PropertyChangeListener extends Java.util.EventListener {
void propertyChange(PropertyChangeEvent evt);
}
Un autre est Java.util.Observable
Qui fournit le mécanisme de radiodiffusion, mais ce n'est pas non plus la meilleure chose à imho.
J'aime ElephantListener.onStomp()
Une autre option est le modèle de tableau blanc . Cela déconnecte l'éditeur et les abonnés les uns des autres et ne contiendra aucun code de radiodiffusion. Ils utilisent tous les deux simplement un mécanisme de messagerie pour pub/sous et ni connexion directe à l'autre.
Ceci est un modèle commun pour la messagerie dans une plate-forme OSGI.