気がついたら早10月じゃあないですか、はや!(*_*)去年はこの頃にDelphi7を購入しています(^O^)さすがほぼ毎週日誌を付けているだけあって、あの頃何をやってたか、非常にわかりやすい……ずーっと三國志製作(ToT)いい加減できててもおかしくないんですけど、恐るべきことに、プログラムはできずに、言語を買ったり、データベースを使ってみたり、オブジェクト指向を学んだり、さらにとうとうデザインパターンにまで踏み込んでしまいました(^^;Aうーん、この1年、なかなか中身が濃いというか、離れていってるというべきか…(~_~;)
で、そのデザインパターン。前回一気に読み終えた『オブジェクト指向のこころ』ですが、結局中身についてはほとんど語っていません(^^;;オブジェクト指向を語るときにはいつも、従来の手続指向を長々語っていたのと同じように、前回も、新しい、デザインパターンによるオブジェクト指向を語るときは、従来の、思いつきによるオブジェクト指向を長々と語ってしまっている、と、こういう風な感じなんでしょうか(^^;A
それでも、学んだことを身につけるには人に教えることが一番効率的、という法則に基づき、いや、新しいオブジェクト指向を学んでいるのが三國志製作そのものですんで、今回はりきってデザインパターンによるオブジェクト指向を検討研究いたしましょう(^O^)
とはいえ、『オブジェクト指向のこころ』では、全部で23あるデザインパターンのすべては紹介されていません。うち12個です。少ない、といえば少ない、しかし最初から著者のいうとおり、この本はデザインパターンの解説本ではなく、デザインパターンを元にした、オブジェクト指向の学習本なのです。本物を見続けているからこそ本物と偽物の区別がつく、といわれるように、いいもの、いいデザインのパターンをわかって、使えるようになってこそ、パターンにない、いいデザインをすることができる、と、こういうわけなのです。
ここまでは著者がそう書いているので自信を持ってそう言えます( ̄^ ̄)ここからが問題。読書感想文でも解説どおりのことしか書けないことが多いように(^^;A実際にわかっているかどうかは、著者がなんといっているかを書くのとはまったく別です。手さぐりでもいいので進んでみましょう…
これまでの方法は、『オブジェクト指向開発講座』にそうする、と書かれていて、『オブジェクト指向のこころ』でもそうするものだと言われていた、とあるように、仕様書から名詞をひっぱりだしてオブジェクトとする(たとえば仕様書に、武将が城を攻め取っていくゲーム、とあれば、武将と城がオブジェクトとなる)。それから、オブジェクトにくっつく動詞をメソッド(≒機能)とする(武将オブジェクトは城オブジェクトを「攻めとる」)という感じになります。
そうやってオブジェクト図を作っていくことになりますが、これで正しいのか、うまく作れているのかはちっともわかりません。ゲームでは武将がいろいろなことをしていくわけですから、武将ができること、メソッドがどんどん増えていくわけです。しかし、武将は実際は、プレイヤー様の命令によって動くわけですし、不幸にしてプレイヤー様の配下ではない武将どもはというと、私が設計する(^^;;コンピュータ思考ルーチンが指図するわけです。となると、実は武将自体は、動かされているわけなんですよね。もちろん武将自身が勝手に動くようにしたいとも企んでいるわけですけども、その、武将の頭脳(衝動?)にあたる部分は、結局武将それ自身とは別のところにあるような気がするのです。
さらには、実際のプログラムを作る段階(実装段階)ではじめて気がつくんですけど、プレイヤー様の命令に従う武将は、プレイヤー様が命令をくだすその手段、つまりユーザインタフェース(UI)に明らかに大きく影響を受けています。オブジェクト指向的にいえば強い関連がある、『オブジェクト指向のこころ』でいえば結合度が高いということになります。そうなると、武将オブジェクトは、リストやボタンなどUIと直接やりとりをはじめることになります。確かに命令を受ける先は武将オブジェクトながら、なんでもかんでも武将オブジェクトに詰め込むならば、これではオブジェクトに分けた値打ちがなくなります(*_*)この辺りで私もさすがに気がついてきたんですよね。なんだか妙だ…!使うUI、使われるUIともども、きわめて武将オブジェクトと密接な関連を有しすぎています。そこまで武将オブジェクトが具体的なUIを操作したり、UI側が武将オブジェクトの中身まで左右するなんて…?
デザインパターンで取られているパターン、特徴のひとつは、オブジェクトを使う側からは、そのオブジェクトが具体的にはどうしているのかが隠されているということが上げられます。オブジェクト指向自体、最初からその特徴のひとつとしてカプセル化、外からは中が見えないという特徴を有しているとされていますが、デザインパターンでは、それを極限まで引き上げようとしているようなのです。たとえば、A社のテレビもB社のテレビも、中身はどうなっているのかまったくわからないながら、同じような操作で番組が見れます。で、A社のテレビが映らなくなったので修理に来てもらったところ、実は基盤の設計不良で、まったく違う新型基盤に取り替えてもらってきちんと映ったとします。それでも、A社のテレビは同じような操作性で番組が見れます。我々としては、基盤がどうなっていようが、部品がなんであろうが、同じような操作でテレビが見れたらそれでいいのです。これがカプセル化のメリットです。使う側は詳しく中身を知っていなくてもいいのです。むしろ、勝手にさわらない方がいいとされます。
まったく余談ですけど、パソコンというのはカプセル化が中途半端なんですよね。だから家電とはかなり異質な製品なんです。ユーザーがかなり中身をいじることができますし、ユーザーが中身をいじらなければきちんと使えない、ということもあります。同じような内容ながら、きっちりカプセル化が進んでいるのが携帯電話です。メールとネットしかしない人にとってはパソコンも携帯も同じですけど、その分、いろいろ設定が必要なパソコンは面倒に感じるかもしれませんね。反面、携帯はその設計によって操作性が全然異なり、携帯を変えると操作を覚えるのが面倒だったりしますよね(~_~;)パソコンはこれとは逆で、OSがWindowsばかりなので、どの会社、どのデスクトップ、どのノートで、部品が全然違うものだろうと、同じような操作性です。一口にカプセル化と言っても、どの面を取るかで話が変わってきます。
同じように、オブジェクトのカプセル化といっても、単にデータだけを外から勝手に操作できないよう、変数に変数操作機能を付けただけ、というものから、何をどうしているかまったくよくわからないながら、こうしてね、とお願いしたら、きちんと結果が返ってくる、というものまでレベルが異なります。私がこないだまで、オブジェクト指向によってプログラムが楽になった、といっていたのは、この、こうしてね、とお願いしただけで勝手に答えが返ってくるように見えることからなのです。もちろん、勝手に、といいつつ、オブジェクトが実行する部分はきちんと作らないといけないんですけどね(^^;A
それでも、同じ機能を何度も使うような場面では、オブジェクトにその機能が移っていれば移っているほど、楽ができます。たとえば単純に、マップ上でクリックした城がどの城か判定したいという機能があったとします。もちろんこれには武将の移動先を指定するときや、単に情報を表示したいとか、内政を実行したいときや、いろいろな場面があります。
手続指向の最たる方法だと、それらのコマンドごとに、毎回、クリックした時の座標を取得して、城一覧から該当する城を判定して……ということを書きつらねることになります。これをサブルーチンとして、それらのルートから外すことが次の段階です。それでも、それぞれの場面でいろいろな事情はありながら、サブルーチンは同じ内容であるために、とにかくサブルーチンに行く前に必要な情報を整備して準備しておかなければなりません。もちろんうまくサブルーチンを書けば書くほど、各場面で用意する情報は減ります。とはいえ、サブルーチンに少しでも合わなければ、そのままでは使えないので別に作るか、事前や事後に別にそのままでは使えないものの調整部分を準備する必要があります。
これがオブジェクト指向になると、毎回の場面で、城またはマップオブジェクトに、今クリックされている城はどれか、と問い合わせることになります。オブジェクト指向度が上がれば上がるほど、毎回の場面がオブジェクト同士のやりとりになります。移動や内政するなら武将オブジェクトから城オブジェクトに、情報表示したいなら城オブジェクト自体に、リストオブジェクトから命令が飛ぶごとに、それぞれのオブジェクトのやり取りになります。
さらにこれにデザインパターンを当てはめることができるんでしょうね。どのデザインパターンなのか、全部を知らないのでわからないんですけど、その発想からすれば、城を指定したい、ということを受けるオブジェクトと、実際にマウスの位置と城のリストとを一致するかどうかを判定するオブジェクトとを分離するということになりそうです。なぜこれがいいのか?
私も何度も一から三國志を作り直しているわけですが(ToT)その原因の大きいものとして、UIの変更があるということがありました。城の指定やコマンドなんかは、方法も違えば内容もまったく違っていたりします。逆にコマンド指定のためのUIによってコマンド内容が左右されることもあります。ルール自体が定まっていないという話もありながら(~_~;)もしルールがきっちり定まっていたとしても、UIと実際の操作をプログラムする部分とが密接に関連していたとすれば、UIの変更は全体の変更とほとんど変わらないでしょう。手続指向の最大の難点はここで、ルールをおいそれと変更できないのは、ルールに基づいてUIから実際の結果に至る一連の流れがプログラム上決まっているからです。SWGで戦艦5万隻が実現できないのは、生産上限を前提にプログラムが作られているからなのです。
だったらオブジェクト指向ならうまくいくかというと、先程お話した通り、私がこれまでとっていた方法は、武将オブジェクトが右クリックメニューから命令を直接受け、武将オブジェクトから城オブジェクトに、どの城を選択しているかということを問い合わせ、マップオブジェクトに問い合わせをした城オブジェクトからの答えによって、武将オブジェクトが自身のデータを変更する、という内容です。右クリックメニューだとかマップのクリックだとかこういうUI部分と、武将オブジェクトだとか城オブジェクトだとかの中心オブジェクトとがかなり密接に関連しています。当然UI部分の変更は中心オブジェクトにも影響を与えるわけです。
これをデザインパターンのこころを理解したカプセル化で行うと、武将オブジェクトや城オブジェクトと、UIオブジェクトとを直接やりとりさせないことにつながるのです。つまり、武将オブジェクトは、武将の移動をしたければ、その操作の中ではここからそこに移動したい、という意図だけ書かれるべきで、実際の、マップ上指示してどうのこうの、ということは分離する、つまり、武将オブジェクトから見えなくする、隔離するわけです。そうすることで、UIが変更になって、マウスクリックからタッチパネルになっても、武将オブジェクトはとにかくここからそこに移動したい、ということは変わらない、変えるべきところはUIと、UIと武将オブジェクトを橋渡しする部分だけで済む、とこうなるわけです。多分これはBridgeパターンのような気がしますね。まさに橋です。
そう考えると、武将の移動だからといって、移動先の城を城オブジェクトに問い合わせたりだとか、クリックしているのがどこかとか、そういう内容は武将オブジェクトの中に取り込むべきではありませんね。武将オブジェクトが責任を持つのは、移動の命令が出れば、指定された移動先に現在の所在データを書き換えることだけです。武将オブジェクトに移動命令を出したり、移動先を指定してやるのは、武将オブジェクト自らではなく、何か別の存在です。ここにおそらく、UIオブジェクトと、プレイヤー様オブジェクトが登場するような気がしてきます(^^;A城オブジェクトにしても、自分自身が指示されているのかどうかを判定するのは、本来違う何かなんでしょうね。クリックされているのはマップです。城そのものではありません。では、マップオブジェクトなのではないか?
このように、なんでもかんでも自ら実行する巨大オブジェクトを解体して実行部分を細かいオブジェクトに分散、しかしながら外からは、もとの巨大オブジェクトが行っていたのと同じように、きちんと窓口として応答するようにする抽象オブジェクトに役割分担する、この発想がどうやら重要なようです。で、その分散して統合する効率的で美しい方法が、デザインパターンで示されている、と、そういう感じのようです。
確かに、巨大なメインルーチンだったものをサブルーチンに分割していったように、巨大なオブジェクトも分散し、協調させていくべきなのです。特にその方法として、ある機能を、オブジェクト自身に実装させるのではなく、別のオブジェクトに分離させ、もとのオブジェクトに所有させるというやり方が、目からウロコです(;_;)オブジェクト自身にその機能があることを、その機能がある別のオブジェクトを持つということに変える、普通に考えていればなんでそんな邪魔くさいことをするんだろう、という気はします。ここが手続指向からオブジェクト指向に移った者の落とし穴なのかもしれません。どういうことかというと、これは巨大メインルーチンからサブルーチンを分離していった方法と同じものだからです。せっかくオブジェクト指向に移ったのに、なぜまたメインルーチンからのサブルーチン切り出しのようなことをしないといけないのか…
オブジェクト指向を理解すると、これまでの手続指向を全否定したくなってしまうんです。そのため、思いつく限りの機能を次々ひとつのオブジェクトに実装させてしまうのかもしれません。しかし、少なくとも巨大メインルーチンから、共通のサブルーチンを切り出していくことは、重複を省くといういい面もあったのです。そして巨大メインルーチンはどこに問題があるのかわかりづらく、また、修正を行ったとき、どこに影響が及ぶかわかりにくいという問題があったのと同様、巨大オブジェクトは一度修正することになると、巨大オブジェクトを使っている方にもどこに影響が及ぶかわからないくらい大きな波紋を(しばしば津波レベルで)及ぼしてしまうのです。
これを避けるため、特に内容に修正が起きやすい機能を別オブジェクトとして切り出し、窓口=抽象オブジェクトに所有させるというのは、言われてみなければ気がつかないのです。なんだかもやもやして、危なそうだな、と感じたのもそのはず、巨大オブジェクトはまさに修正があったときの甚大な影響があるのです。機能(、と言い続けると、手続指向的に陥るらしいので、振る舞い、というべきでしょうか)を別オブジェクトにして持つ、また、抽象オブジェクトとして機能を統合し、それを使うものは抽象的に使う、ということを考えていくべき、らしいのです。
たとえば、武将オブジェクトは統合窓口であって、「移動する」オブジェクトや「内政する」オブジェクトを持つ、と。武将オブジェクト自体に移動や内政の細かい内容、能力から成否を判定したりだとかは持たず、それらは「内政する」オブジェクトに持たせる、と。能力判定オブジェクトなんかもあったらよさそうですね。ただ、武将オブジェクト自体は、これらのオブジェクトを、自分自身の振る舞い、機能として持っているふりをします。というより、デザインパターンにより、持っているふりができるように設計します。そうすることにより、武将オブジェクトを使う、たとえばプレイヤー様オブジェクトなんかは、武将オブジェクトに対し移動せよ、と命じるだけですむのです。武将オブジェクトは「移動する」オブジェクトにその命令をこれまた伝えるだけです。「移動する」オブジェクトは移動させるための私の操作性感覚(^^;Aに従いUIオブジェクトとやり取りするわけですけど、私の操作性感覚がその後に変わっても、UIオブジェクトと、「移動する」オブジェクトとUIオブジェクトとのやり取り部分を変えるだけで済みます。武将オブジェクト自体や、武将オブジェクトを使うプレイヤー様オブジェクトには影響が出ません……もちろん、コマンド自体の操作性が変われば、この辺りも変わるんでしょうけど(~_~;)
こういう新しい視点で作り直し、いや、リファクタリングしてみれば、おかしな設計図に基づくおかしな完成に至らなくて済む、はずです。ただ、ま、まだきっちりデザインパターンの心髓は、まだ理解しているのか、理解できていないのか、この辺りが多分、まだ問題ではありますね……!
|index|
このページへのリンクはフリーです。