Я думаю о следующем примере, чтобы проиллюстрировать, почему контравариантность полезна.
Рассмотрим схему GUI с Widgets
, Events
и Event Listeners
.
abstract class Event;
class KeyEvent extends Event
class MouseEvent extends Event
trait EventListener[-E] { def listen(e:E) }
Пусть Widgets
определяют следующие методы:
def addKeyEventListener(listener:EventListener[KeyEvent])
def addMouseEventListener(listener:EventListener[MouseEvent])
Эти методы принимают только "конкретные" прослушиватели событий, и это нормально. Однако я хотел бы также определить слушателей "кухонного раковины", которые слушали все события и передавали таких слушателей методам "добавить слушателя" выше.
Например, я хотел бы определить LogEventListener
для регистрации всех входящих событий
class LogEventListener extends EventListener[Event] {
def listen(e:Event) { log(event) }
}
Так как признак EventListener
является контравариантным в Event
, мы можем передать LogEventListener
всем этим методам "add listener", не теряя при этом своей безопасности типов.
Имеет ли смысл?