[635] オブジェクト指向
投稿者:sion
2007/02/20 02:13:25
大変な長文失礼します
興味深く読ませていただきました。
世の中の多くの解説は
「クラスとインスタンス、そして継承。及びパッケージ化」があればオブジェクト指向である。それがオブジェクト指向の本質である・・・かのような誤った物が多いです。
クラスや継承、ブラックボックス化は、たしかにオブジェクト指向の重要な構成要素になる「事がある」かもしれませんし、便利な物かもしれませんが、それがすべてではありません。
現在存在するオブジェクト指向言語と呼ばれる物もそういった意味では不十分な物ばかりです。
そのような中で、前橋さんのHPの解説はとてもすばらしい物と思いました。
ただ、「なぜわからなくなってしまうか」のページの説明で
「オブジェクト指向をわかりにくいものにしている最大の要因として、「メッセージ」という言葉が挙げられます。」
とあります。
もちろん、これは「現在存在するオブジェクト指向と呼ばれる言語では、実質関数呼び出しなのだからわかりずらい」と言われているのだと思います。
しかし、オブジェクト指向の世界では「メッセージは非常に重要な要素」ですから、この表現では、「オブジェクト指向の世界ではメッセージは重要でない」と誤解されてしまうおそれがあります。
あと、
「カプセル化とは、「実装詳細の隠蔽」のことです。外部に対しては必要最低限のインターフェースのみを公開し、それ以外は隠蔽することで、実装の変更を可能にしたり、そのモジュールを他でも使いまわすことを可能にする、という概念です。」
と有りますが、これは誤りです。
「実装詳細の隠蔽」は、確かに良い事ですし重要ですが、カプセル化の本質は「メッセージのやりとりを行う単位を作成する」ことです。そして、これがオブジェクト指向の根本です。
オセロの例がありますが、「石を置く」「置けるかチェックする」「盤面を初期化する」「マスの状態を返す」の関数をサンプルとしてありますが、これでは不十分です。
何が足りないかというと、「マスそのもののオブジェクト」です。
8x8=64のマスすべてをオブジェクトとする必要があります。
すると、「え?8x8の配列で良いでしょう!?」と思われるかもしれません。
それでは、次のような話を持ちかけられたらどうしますか?
「オセロゲームの新しいルールを作ったので、それを反映してください。そのルールとは、4隅が無い物です」
実際、4隅が無いオセロなんてつまらない物かもしれませんが、まあ、例と言う事で・・。
このような話が持ちかけられたら、残念ながら前橋さんのサンプルでは大きなプログラム修正が必要になってきます。
たとえば、盤の初期化。
真ん中の4石以外はすべてクリアすると思いますが、おそらくC言語的に書くと
for (y = 0; y < 8; y++)
for (x = 0; x < 8; y++)
ban(y,x) = 0
みたいに書くのだと思いますが、これでは、この処理を大きく変更しなければ成りませんね。
何しろ4隅が無いのですから。(まあ、「4隅の分データを無視すれば良いのでは」とか言う話は置いて置いてください。)
石が置けるかチェックする処理なども同じです。
本来のオブジェクト指向の考えでは、たとえば盤のマス一つ一つをオブジェクトにします。
そして、それらのマスに「あなた(たち)の中身をクリア(石がない状態にする)しなさい!」と「メッセージ」を送ればよい事になります。
そう、8x8-4=60のマスすべてにメッセージを送るのです。
「結局60のマスに送るとき、ループ処理するのでは?」と思われるかもしれませんが、それは、現在のオブジェクト指向言語の不備の問題であり、本来のオブジェクト指向の考えでは、60のオブジェクトに大号令すればよい事になります。
たとえば、 masu(all): message (CLR) みたいに。
もちろんこのような例で書ける言語はありません。私の勝手な文法です。
60人いる保育所の子供全員に「みんなー!クリアしなさい!」と叫ぶ先生のようです。
この方法だと、盤が8x8だろうが、4隅が欠けていようとも、6x10のマスであろうが、コーディングを変える必要はなくなります。60人の子供たちは、必死に自分のマスをクリアする事に専念します。
盤の形の変更はマスの初期配置処理(インスタンス生成)さえ変えればよい事になります。
「石を置けるかどうかチェックする」ルーチンも同じです。
60のオブジェクトたちは、互いにメッセージをやりとりしあい、石をひっくり返す事ができるか確かめて答えを返す事になります。
たとえば、「マスに石が置けるかチェックする」は、自分の8方の隣のマスに問いかけます。「今、僕のマスに白を置こうとしているけど、君のところは黒かい?そして、盤が切れるまでの間に、白有るかい?」「僕のところは黒だけど、隣については聞いてみるね」などなど・・・。
この方法だと、たとえ、隣に突然穴があいていたとしても関係有りません。盤の形が変わっても関係有りません。オブジェクト同士がメッセージのやりとりで処理しますから。(もっと根本のルール変更が有ればこのオブジェクトも修正が必要になりますが、修正はこのオブジェクトのみになります。)
とても回りくどい、面倒な方法に思われますが、実際のコーディングで表せば、一般的なやり方と量はさほど変わりません。
「’石を置く’、’置けるかチェックする’、’盤面を初期化する’、’マスの状態を返す’の処理を一つにまとめてオブジェクトにしただけで、根本は変わらないのでは?」という声が聞こえてきそうですが、違います。
「マス」というオブジェクト(部品)が作成されています。この部品を利用して、オセロに似た別のゲームができるかもしれません。たとえば、時間とともに盤に穴があくオセロとか・・・。
その例ですと、「時間とともに盤に穴をあける」という処理を追加すればよいだけですが、従来のやり方では、おそらく全面書き直しでしょう。
すると、「結局は穴があくのを前提にマスのオブジェクトを記述しなければならないのでは?」という声が聞こえてきそうです。
たしかにそうです。また、白、黒の他に「赤」という石が追加になったら記述を追加する必要があります。
しかし、その追加はオブジェクト(クラス)についてすればよい事になります。その際は、それこそ「継承」を使って派生クラスを作り、赤石の処理のみを追加すればよいかもしれません。
これで、部品の組み合わせにより「白黒64マスの昔ながらのオセロ」「4隅のないオセロ」「白黒赤石のある64マスのオセロ」「時間とともに穴のあくオセロ」など、様々なバリエーションを作る事ができます。
しかし、従来のコーディング技術では、おそらくバリエーションの数だけプログラムを全面書き直す事になるでしょう。もしくは、if文の嵐になるでしょう。
今度は、「じゃあ、そのマスを関数やサブルーチンにすれば良いのでは?」と疑問があがるかもしれません。
はい、それでかまいません。オブジェクト指向の「本質」は、クラスやインスタンス、継承やブラックボックス化することではなく、「オブジェクト単位で扱うことの考え方」ですので。
場合によっては、昔ながらのBasicでも、その本質は記述する事はできます。(読みづらいでしょうが)
オブジェクト指向におけるオブジェクトとメッセージの重要性、わかっていただけたでしょうか?
なお、この意見は私の個人的な意見ではありません。20年以上オブジェクト指向に携わってきた経験により他の人からのアドバイス、文献から得た物であります。
ところで、私の文章の中には
「本来のオブジェクト指向の考え」という言葉があります。
「本来の・・・って、誰がいつ考えた物が本来なんだ?」とつっこまれそうですね・・・ただ、現在主流のOOPでは、生産性の向上なんてあり得ない気がするのは確かです。
蛇足ですが、20年以上前から有るGPSS等のシミュレーション言語では、オブジェクトを複数生成してメッセージをやりとりしながら、すべてのオブジェクトが(論理的に)同時進行で処理を行います。
内部的に関数コールでしょ!?って・・・いえ違います。