RubyのMix-inによるColorUtilの解決!?

by tanabe on August 08, 2005

fladdict.net/blogさんの「OOP全盛期だけど、手続き型がマイブームになってる(前)」を読んで、んー、これってMix-in的なあれなんだろうか、とかうだうだ考えていたんだけど、ちゃんと考える時間がなくなったんで、とりあえずメモだけして寝ることに。

OOP全盛期だけど、手続き型がマイブームになってる(前)
http://www.fladdict.net/blog-jp/archives/2005/08/oop.php

じゃあ、なんで「手続き型」がいいのかというと、手続き型だと他人のライブラリを導入するときや、自分のライブラリを再設計するときに、既存資産の運用がく柔軟にできるのではないかと思ったりしたんです。

oo的な方は、Colorの実装の継承をしてColorHSBを。Colorの実装の継承をしてColorGrayを。んで、両方を利用できる新しいクラスを作りたい、と。でも内容的に多重継承はNGなんだろうな。

で、これを手続き型の方で解消している手段として、ColorUtil.setHSBの中にColorHSBクラス的な処理を閉じ込めていると。

そして、ここからが面白い。

で、ここからが応用。
「手続き型」は関数の呼び出し作業が煩雑なのがネックなわけですが、これをOOPで解消するっていうのはどうでしょう?手続き型関数ColorUtilを作成した上で、Colorクラスを拡張してColorHsbを作ります。そして、ColorHsbのsetHSB()の処理では、内部的に ColorUtil.setHSB()を呼び出すように処理するわけです。


function setHSB(h, s, b){
ColorUtil(this, h, s, b);
}

こうすると、ユーザー的には手続きを意識しないでOOPで作業ができます。またColorGrayのような他人のクラスであっても、 ColorGrayを拡張して内部でColorUtilにバイパスしてやれば、ColorGrayにsetHSBを実装するのも一瞬ですみます。超楽チン。変に多重継承するわけでもないので、オブジェクトツリーがレガシーで埋まることもなく、自分のライブラリをブラッシュアップとかするのも凄い楽になります。

こうすると、OOPの利便性を機能を保ちながら、オブジェクトとアルゴリズムを分離できるんじゃないかと思ったわけっす。処理は微妙に重くなるけど、最近のパソなら大丈夫っしょ。

これって、ちょっと実装上は違っているけど、発想は完全にRubyのMix-inですよね?

「なんだ車輪の再発明じゃん。」ていう意味ではなくて、自分で考えてここまで来ているってすごくないですか?

私は答え(Mix-in)を先に知ってしまったので、あー、なるほど。うんうん。というかんじでしたが、Ruby&Mix-inを知らずに何もヒントなしにこれを自分で応用できたかというと疑問です。(いつかは何かを読んでたどり着いたかもしれませんが)

読みながら純粋に感動してました。

 

で、Ruby的な模擬コードを書いてみたので、書いておく。

class Color

  def setRGB(r, g, b)
  end

end

class ColorHSB < Color # オリジナルの拡張クラス・Colorの実装を継承

  def setHSB(h, s, b)
  end

end

こいつが元々の状態。

で、ColorGrayが出てくる。

class ColorGray < Color # ライブラリの再利用・Colorの実装を継承

  def foo
  end

  def var
  end

end

このsetHSBの手続き型プログラミング的な解法をRubyのMix-inを利用してやると、こんな風にまとまる。

module ColorUtil # これがMix-inモジュール

  def setHSB(h, s, b)
    # 実装上は、Colorクラスの仕様継承(同じAPI)のものはなんでもOKな実装をする。
    #   >他人が作ったColorGrayクラスであろうとも、その親クラスがColorクラスである限り、
    #   >apiを介してrgb値にアクセスするならばなんの問題もないわけです。
    # の通りだ。
  end

end

class Color

  def setRGB(r, g, b)
  end

end

class ColorHSB < Color # オリジナルの拡張クラス・Colorの実装を継承(Mix-in改良版)

  include ColorUtil # ColorUtilのMix-in。ColorUtilの実装を混ぜ込み継承。

end

class ColorGray < Color # ライブラリの再利用・Colorの実装を継承

  include ColorUtil # ColorUtilのMix-in。ColorUtilの実装を混ぜ込み継承。

  def foo
  end

  def var
  end

end

これでどうなるかというと、ColorHSBのインスタンスからもColorGrayのインスタンスからもsetHSBが呼び出せるようになる。

わかりやすいようにここではColorHSBというクラスをそのまま拡張して作成したが、実際にRubyでプログラミングする場合はColorHSBは作らずにColorクラスに追加でinclude ColorUtilだけしてやると思う。(ケースにもよるとは思うが。)

そうすると、Colorを継承しているColorGrayは自動的にsetHSBを使えるようになる。

なんやかんやで最終的なイメージはこんなかんじ。

module ColorUtil

  def setHSB(h, s, b)
    p 'setHSB called !'
  end

end

class Color

  include ColorUtil

  def setRGB(r, g, b)
  end

end

class ColorGray < Color

  def hoge
  end

  def var
  end

end


<実行サンプル>

c = Color.new
c.setHSB 240,100,100

=> "setHSB called !"

g = ColorGray.new
g.setHSB 240,100,100

=> "setHSB called !"

てなかんじ。Love Ruby!

「OOP全盛期だけど、手続き型がマイブームになってる(後)」もあるようなので、期待してます。

# うわぁ、全然「メモだけして寝ることに」にならんかったー!



この記事へのトラックバック
Ruby Mix-inの詳細については、まつもとゆきひろさんの日経Linux 2005年7月号の連載「まつもと直伝プログラミングのオキテ 第3回 多重継承の光と影」に詳しいので、気になった方には強くおすすめ。 日経BPの記事検索サービスでこの記事だけのダウンロード購読もできます.
Mix-inについて追記。【満足せる豚。眠たげなポチ。】at August 08, 2005 04:30