カメニッキ

カメとインコと釣りの人です

Rubyの「継承」と「Mixin」使い分け

「クラス」について、
クラスは「型」なので、クラスを作るということはちょっと極端な言い方だけど新しい型を作るとも言えます。

[1,2,3,4]はArray
"hoge!"はString

これの仲間として○○型が追加されることになる。
で、それを継承してつくるサブクラスは○○型の派生△△型を作っていることになる。

型理論で「リスコフの置換原則」では、

型のオブジェクト に関して真となる属性を とする。このとき が の派生型であれば、 型のオブジェクト について が真となる。

と述べられている。
これはつまり

子は親の一種

ということになる。
例として「犬は動物である」「飛行機は乗り物である」など。
プログラム作成時にもスーパークラスとサブクラスの関係はis-aとして表現される。

しかし現実にはis-aよりもhas-aの方が多く存在している。
にも関わらず、「継承」という仕組みでしかコードの共有が出来なかったため、しょうがなく、いい加減に捻じ曲げis-a関係にないものを無理やりスーパークラスとサブクラスの関係にしていました。

これは意味的におかしいという問題だけはなく、親と子が必要以上に結びついてしまい親クラスの変更に子クラスが大きく影響を受けてしまうため、規模が大きくなるにつれ親クラスの変更が困難になってしまいます。

これを解決するためにmixinというメタプログラミングが登場しました。

これまではFugaのコードを共有して使いたい場合、親子関係にない場合もHogeを作成するときに継承を使って

class Hoge < Fuga

end

としていました。

これをmixinに置き換えることで

class Hoge
 include Fuga
end

とすることができます。
FugaコードをA,B,C,Dの4箇所から呼び出している場合に
A,BのためにFugaを修正したい時、C,Dへ影響が大きく困難だと判断出来れば無理してFugaを使用せず別のFuga2というmixinを作成しincludeするなど柔軟に変更が可能になります。