反変性が役立つ理由を説明するために、次の例を考えています。
Widgets
、Events
、およびを使用した GUI フレームワークを考えてみましょう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
それは理にかなっていますか?