はじめに
オブジェクト指向について、最初自分はの本やウェブサイトに書いてあることが全然理解できませんでした。世の中のモノをモノとしてそのまま扱えるようにした?クラスとインスタンスはたい焼きの型とたい焼き?
プログラムとたい焼きが何の関係があるんじゃー!!わからんわボケ!!
……取り乱しました。
とにかく説明がイマイチでうんざりしておりました。JavaやRubyと10年くらい戯れてみた結果、何とか自分が納得した理屈で説明をしたいと思い、このコラムを書きます。
対象読者
- オブジェクト指向でつまづいちゃって聞いただけで寒気がする人。
- オブジェクト指向ってなんぞなと思いながらいまいち釈然としないまま使っている人。
クラスとインスタンス
クラスは遺伝子です!インスタンスは生物です!
ほぼこれで終わりなんですが、ちゃんと補足します。
生き物は一つの受精卵から始まって、身体が作られます。その設計図となっているのが遺伝子です。ヒトの遺伝子はヒトそのものではありません。これが「たい焼きとたい焼きの型」のメタファーで言わんとしていることだと思います。
そして「たい焼きの型」で説明できない「継承」の概念を遺伝子ならうまく説明できます。(突然変異を除けば)子供が持っている特徴は全て親ないしその先祖から脈々と受け継がれてきたものです。それは遺伝子に刻まれています。
例えばある猫が耳をかじられて片耳になってしまったとします。でもその子供は片耳になったりはしません。それは片耳であるという情報が遺伝子には記録されず、新しい子猫が生まれるときに片耳という情報が受け渡されないからです。クラス(遺伝子)とインスタンス(生物)は違うものですから。
継承とその弊害
クラスが遺伝子だとすると、その弊害も見えてきます。今の生き物は約38億年の継承の果てにあるものです。そして残念なことに現在の生物はそのせいで修正不能なバグだらけなのです!
ヒトだけに限って言うと、一番顕著なのが目の盲点。なぜ盲点があるかというと目の神経の配線が非合理的なのを無理やり動くようにしているからです。
目は光を感じるセンサーとその後ろにケーブルがついた視神経の集まりなのですが、普通に設計すると目玉の内側にセンサー、センサーの後ろにケーブルを逃がす穴をそれぞれ作って目玉の外側でまとめるという構造にすると思います。この構造なら盲点は出来ません。ちなみにタコ・イカなんかはこういう構造です。
しかし実際のヒトの視神経はケーブルがセンサーと同じ側に出ています。で目の玉の中でケーブルをまとめて盲点というでかい穴から外に逃がす構造です。魚時代の最初の目の設計の欠点をそのまま引き継いでしまっているのです。
オブジェクト指向において継承が素晴らしい機能ともてはやされた時代もありましたが、現在あまり言われないのはこういった先祖の根本的なバグがあった場合に影響範囲が大きすぎ、修正することが事実上不可能になるからです。
継承より委譲
現在の流れとしては継承してもライブラリのクラスから1回のみとか、コンポジション(委譲)を使おうという方向性になっています。
これは例えて言うと、いろんな匂いをかぎ分けられるようにヒトの遺伝子に犬を混ぜて犬人間を作ることと、匂いを嗅ぐのは犬に任せて、犬から内容を教えてもらうことの違いです。
犬人間を作ってしまうと、犬の鼻の感覚が完璧に理解できるでしょう。ただ、犬のバグも引き継いでしまいます。おしっこの度に片足を上げる変なバグが出るかもしれませんね![]()
対して犬に匂いを嗅がせてその内容を教えてもらう場合、犬が外に公開しているそぶり(しっぽをふる、吠えるetc.)からしか匂いの内容はわかりません。犬が実際にどう感じているかはいわばブラックボックスです。しかし、危険なものがあるかどうかだけを判別するならそれで十分かもしれません。
さらにこの場合の利点は、犬が何かの匂いを誤判定した場合にそれが明確に犬、あるいは犬とのコミュニケーションに原因があるとわかることです。犬人間になってしまうと問題発生時の切り分けが難しくなります。
カプセル化とインターフェース
オブジェクト指向の大きな利点として良く言われるのがカプセル化です。これは、外部に公開するふるまい(インターフェース)はガッチリ決めて、内部はブラックボックスでいい、というより外から余計なことをさせない仕組みです。
この考え方の利点の1つは、外部に対するふるまいが同じであれば、いろんなインスタンスを使い分けられることです。
アヒルの鳴き声を録音したいとしましょう。まず簡単に思いつくのはアヒルを実際に連れてきて鳴かせることです。次に思いつくとしたら、いろんな鳥の声を収録したCDから理想のアヒルに近い声を探すことです。もっと変な方法を考えると、声帯模写の芸人さんにアヒルの鳴きまねをしてもらうことも出来ます。また遺伝子操作でアヒル人間になる手もあるかもしれませんが、それは一応除外します。
アヒル・CD・芸人さん、これら3者にはもちろん親子関係はありません。しかし結果としてアヒルの声を収録する、という目的はどれでも果たすことが出来ます。Rubyではこれをまんま「Duck Typing」、アヒルっぽい声を出せるものは全部アヒルとして扱う、という考え方をとっています。
そしてもう1つの最大の利点は「内部のことを知る必要が無い=内部に干渉できない」ということです。
生き物と同じで明確に境界があるのです。
このアヒル声機能がライブラリとして提供されているとしましょう。オブジェクト指向以前には、アヒルを捕まえる(メモリの確保)、アヒルを鳴かせる、アヒルを放す(メモリの解放)を必ずこの順番に行う事、みたいなマニュアルが必要でした。さらに外部からアヒルの中身をいじくれてしまうので、別の機能の影響でアヒルが鳴かなくなってしまったり、アヒルが暴れだして周りを破壊して回る(メモリ破壊)なんてことも起こっていました。
内部に干渉できないようにして、公開された手順での操作しか許さないことで、こういった事案を防ぐことが出来ます。
まとめ
古いパソコンではすべてを自分でプログラミングしなければなりませんでした。しかし時代が進み様々なライブラリが提供されると、そのライブラリを組み合わせて仕事をさせることの方が多くなりました。GUIなんかになると、もうライブラリを使わないと作れないレベルの複雑さです。
作られたライブラリをより専門的な用途にするために、機能を付け加えることが出来るというのが継承です。そしてライブラリを使う側にはその内部の複雑さを見せないようにし、公開されたふるまい(インターフェース)のみを操作させる、これがカプセル化です。
農家側はよりたくさんジャガイモが出来るよう品種改良する(よりよい遺伝子を残す)、しかし食べる側はジャガイモの生育方法、農薬の散布の方法、細かな性質を知らなくても調理の仕方さえ知っていればおいしく食べられる、こんな感じのイメージで私はとらえています。
今までの説明で余計わからんのじゃボケ!となっている読者ももちろんいるでしょう。ただ、少しでもオブジェクト指向のイメージがつかめたら、そしてアレルギーが無くなれば、このコラムを書いた自分としてこれ以上嬉しいことはありません。