著作一覧 |
構造化するってのは、機能で分けることだという言い回しを見かけることがある。
多分、こういうのだろう。
# 機能=function def open(path) File.new(path, "r") end def read(f) f.read end def close(f) f.close end f = open('foobar') puts(f.read) f.closeで、それに対して、そもそもOOPではどうしたといいだす場合には、
#機能 = use case class FooBar def initialize(path) @f = File.open(path, "r") end def show(f) f.puts(@f.read) end def close @f.close end end foobar = FooBar.new('foobar') foobar.show($stdout) foobar.close
とかいうように、エンティティとして扱えるように、最初のコードではバラバラだった「機能」をカプセル化する。
しかし、カプセル化されているとは言っても、下の3行が3行であることに何の変りもない。メリットはなんだ?
むしろ、この場合であれば
# 機能=feature class FooBar def self.show(path, f) File.open(path, "r") do |file| f.puts(file.read) end end end Foobar.show('foobar', $stdout)
のほうが、よりカプセル化されているのではなかろうか?しかし、結果的に静的なメソッドになってしまった。
はて?
上のは、いんちきがあって、最初のと最後のは視点が異なる。
最初のは、プログラミングとしての構造化で、機能というのは細粒度となっている。与えられたパスからファイルを開くとか、与えられたファイルを閉じるとか。
最後のは、モジュールの導入だ。FooBarというクラスはまったくクラスの必要はなく(インスタンス化を考えてはいない)のだが、与えられたパスのコンテンツを表示するという、最初の例ではメインが実行していた処理そのものを行っている。この場合、FooBar.showの内部実装がOOPLによるものかたとえばCOBOLによるものかは、この粒度からはどうでも良いものだ。
「モジュールを黙殺しちゃってるんです」というのは、最初と2番目(例が無茶だが)とは別に3番目があることを言っているのだと思う。3番目はマルチインスタンスは無視しているが、2番目(あ、ちゃんとaskじゃなくてtellするように引数を使ってたので違う例になってしまった)と同様にtell, don't ask則にしたがっているというのは重要だ。というか、もし2番目でshowメソッドではなくreadメソッドを実装していたとしたら、それは最初のやつよりも手間がかかるぶんだけ、もっと悪い(この処理では同時に複数のFooBarのインスタンスが不要だと仮定している)。
というように、2.5mあたりに視点をおくと、固い3番目のFooBarの亜種をたくさん用意することこそが重要になるので、COBOLのほうがへたなJava(showメソッドではなくreadメソッドを実装するようなタイプ。ゲッタとかセッタとか)より、よほどモジュール化できるため、システムを組みやすいということなのではないか、というように推測してみる。
亜種が複数あるのに対して、ポリモーフィズムは不要なのかといえば、それは設定可能なフレームワークのレベルでサポートされることになる(粒度が粗いというのはそういうことだ)し、そのような外挿しの仕組みのほうが運用に自由度を与えられるからむしろ望ましい(場合がある)。
ジェズイットを見習え |