Je pense à l'exemple suivant pour illustrer l'utilité de la contravariance.
Considérons un cadre d'interface graphique avec Widgets
, Events
y Event Listeners
.
abstract class Event;
class KeyEvent extends Event
class MouseEvent extends Event
trait EventListener[-E] { def listen(e:E) }
Sea Widgets
définissent les méthodes suivantes :
def addKeyEventListener(listener:EventListener[KeyEvent])
def addMouseEventListener(listener:EventListener[MouseEvent])
Ces méthodes n'acceptent que des récepteurs d'événements "spécifiques", ce qui est très bien. Cependant, j'aimerais définir également des auditeurs de type "kitchen-sink", qui écoutent tous les événements, et transmettre ces auditeurs aux méthodes "add listener" ci-dessus.
Par exemple, je voudrais définir LogEventListener
pour enregistrer tous les événements entrants
class LogEventListener extends EventListener[Event] {
def listen(e:Event) { log(event) }
}
Étant donné que le trait EventListener
es contravariant en Event
nous pouvons passer LogEventListener
à toutes ces méthodes "ajouter un auditeur" sans perdre leur sécurité de type.
Cela a-t-il un sens ?