Я думаю о следующем примере, чтобы проиллюстрировать, почему контравариантность полезна.
Давайте рассмотрим структуру 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
всем этим методам «добавления прослушивателя», не теряя при этом безопасность типов.
Имеет ли это смысл?