mixinとは
mixinとは、
オブジェクト指向プログラミングにおける、サブクラスによって継承されることで機能を提供するクラスであり、単体で動作することを意図しないものです。継承は本来、特化を目的としますが、mixinは機能の集約のために利用されます。特に多重継承が可能なシステムでは、複数のmixinクラスを組み合わせることで、容易に機能豊富なクラスを構築できます。
mixinの概要
オブジェクト指向プログラミングにおける継承は、本来は特化を意図したものです。すなわち、継承する側(
派生型)と継承される側(基底型)の間にはリスコフの置換原則があることが前提となります。しかし、実際には実装の再利用の手段として使われることが多く、mixinにおける継承も、特化のためではなく、複数の機能を集めるための手段として用いられます。
多重継承が可能なシステムでは、複数のmixinクラスを多重継承し、複数の機能を持つクラスを簡単に作成できます。例えば、`InputStream`と`OutputStream`というmixinクラスを多重継承して`InputOutputStream`という双方向ストリームのクラスを作成するような使い方が可能です。
mixinの歴史
mixinの概念自体は以前からありましたが、1970年代のMIT系Lisp方言であるFlavorsでその名前が使われ、一般化しました。Flavorsは、同時期のSmalltalkの
オブジェクト指向システムに影響されたもので、多重継承を特徴としていました。mixinという名称は、マサチューセッツ州のアイスクリーム店から着想を得ており、基本となる味(Flavor)にナッツやクッキーなどの具材を混ぜて提供していたことから、「Mix-In」という登録商標が付けられました。
mixinの利点と妥協点
mixinは
コードの再利用を促進しますが、いくつかの妥協点も伴います。例えば、クラスの多重継承ができない環境では、mixinは「メソッド実装付きのインターフェース」と見なすこともできます。クラスがmixinを含む場合、そのインターフェースを実装したクラスは、mixinの属性と操作を取り込みます。この取り込んだ要素はコンパイル時にクラスの一部となります。
インターフェース実装の利点
mixinは必ずしもインターフェースを実装する必要はありませんが、あえて実装することによって、そのインターフェースを必要とするメソッドに、引数としてインスタンスを渡せるという利点があります。
mixinのバリエーション
Rubyにおけるmixin
Rubyでは、クラスの継承は単一継承のみに制限されており、多重継承に伴う問題を避けています。代わりに、モジュールと呼ばれる機能があり、モジュールをクラスに「mixinする」ことで、複数の機能を追加できます。モジュール自体は継承関係を持たないため、菱形継承問題は発生しません。
その他の言語におけるmixin
mixinのような機能を持つ言語は他にもあります。
D言語 (テンプレート・ミクスイン)
Dylan
Perl
Python
Scala
Self
Strongtalk
Object REXX
XOTcl
Groovy
Vala
mixinの例
Pythonでは、C3 linearizationによって多重継承時のメソッド探索順が解決されるため、多重継承が有効な手法として用いられています。`SocketServer`モジュールは、`UDPServer`と`TCPServer`クラスを提供しており、`ForkingMixIn`と`ThreadingMixIn`というmixinクラスを利用することで、ソケットサーバの機能を拡張できます。
例えば、`TCPServer`を`ThreadingMixIn`で拡張すると、コネクションごとにスレッドを生成する機能が追加されます。また、`ForkingMixIn`を使用すると、各新規コネクションに対してプロセスがフォークされます。これらのmixinは、ソケットサーバとしての機能に影響を与えることなく、基盤となる機能を選択可能な形で提供しています。
C#の例
C#では、インターフェースと拡張メソッドを組み合わせることで、mixinと同様の機能を実現できます。
関連事項
トレイト
抽象型
外部リンク
Wiki entry at Cunningham & Cunningham, Inc.
Mixins in ActionScript.
Scala Overview: Mixin Class Composition - a step-by-step example in
Scala
*
The Common Lisp Object System: An Overview by Richard P. Gabriel and Linda DeMichiel