kr_ryo 徒然日誌 <2005年11月20日分>

三國志製作記120〜他のことは考えなくてよい〜

あったか小春日和かと思いきや、一気に寒くなって、突然こたつとストーブが必須になってしまった今日この頃、もう11月も残り半分、早いですねえ〜(*_*)思い起こせば去年の年末頃からデータベースではらちがあかないとオブジェクト指向をやりだし、なんだかんだとやりながらここ1年ですっかりはまってました(^-^)とはいえ、三國志製作最大の難所、いや、SWGでも同じだったんですけど、規模が小さいのでまだましだった、この問題、が、単純なオブジェクト指向ではクリアできなかったため迷走していたのです。で、これは!と思ったデザインパターンではクリアできた、むしろデザパタは「この問題」をクリアするためのものといってもいいくらいと気付いた今日この頃、おかげさまでハイペースで進んでます(^O^)

さあ、みなさんもデザパタの威力を知りたい場合はココをクリック→クリック!

と、いうのは冗談で(^^;;別に特別なソフトを必要とするわけでもなく、単なるオブジェクト指向言語であるだけで、デザインパターンを使えばこれだけ簡単になる、という見本をお見せしましょう…

まず、私が何に苦労していたかというと、昨年まで、オブジェクト指向でない、私が言うところの手続指向言語であった場合に何が起こるかということからお話します。たとえば、リストに武将の一覧を表示させて、一人を選択し、そいつをある城からこの城へ移動させることを考えてみましょう。

手続指向言語は、プログラムが何をするかという手続を順番に書きつらねる、いかにもコンピュータ的な方法です。ですので、移動という命令があれば、リストを用意し、武将の一覧を表示させて待機し、ユーザーが適切にその中の一人を選択した場合、移動可能城を判定した上で、移動可能城を表示して待機し、ユーザーが適切な移動可能城を選択した場合、武将の位置情報を更新し、また最初の命令待ち状態に戻す、という一連の手順を途切れず用意する必要があります。もちろん、適切な一人を選択せずに、どこか別の場所をクリックした時とか、キャンセルしたい場合の処理を別に用意しなければなりません。また、移動可能の城が無い場合や移動できる武将がいない場合、移動という命令を実行できないようにするか、それとも途中で移動できる人や城が0であるということで、その旨表示するか、あかんねんな、とキャンセル待ちにするか、という処理も考えないといけませんね。

余談ですが、移動可能でない場合、つまり移動可能武将が0だったり、所有城が1つで、移動できない場合、先程の3つの方法のうち、どれを取ろうか迷い中です(~_~;)最もスマートなのは、そもそも移動というコマンドを用意しないことです。状況感知型ですね。ただ、どうして移動コマンドがないのかわからないので、勘違いしていると、バグだ!と思ったりするわけです。私の使っているDelphiでも、プログラムの最中、式の左が文字列型を予定している場合、式の右側に数値型の変数をだそうと思っても、自動表示では数値型のものは出ないので、なんで?と思うことがあります。当然文字列型変数=数値型変数、というのは、数値型を文字列型に型変換して、ということでできるんですけども、型変換があってはじめて数値型を出してくれるのです。まあ、エラーを未然に防いでいるといえば防いでいるんですけども、一瞬???(?_?)と思います。

次の、移動を選んだら、理由を示してエラー表示してくれるという方法。SWGがまさにこれですけど、作り込むと状況感知型と同じくらいの手間がかかるわりに、そんな表示できるくらいなら最初から選ばせるなよ、と思ったりすることもあるわけです。私だけでしょうか?(^^;;わがままなもんですけども、ついうっかり選んだりすると、そう思ったりもします(^^ゞまた、できない理由はわかるものの、その理由を示すダイアログなんかを閉じたりするのも邪魔くさいと思ったりもするんですよね〜!(~_~;)

先の2つが、できないことをしようとする人のためにわざわざ作り込んでまでおせっかいな、普段と違う状況を用意するわけですけども、放っておく、という第3の方法もあります。武将を選んでから、移動可能城がないと、あ、移動する場所ないや、と気づく、という方法、というか、何もしない、です。プログラマーとしては作り込む手間が省けます。理由にしても、いちいち言われなくとも自ずからわかる、というメリット(?)もあります。移動できないなら最初からできないようにしてくれよ、という思いは作り込んだエラー表示型と同じなので、状況感知型を取るまでは同じです。

ということは、エラー表示型はおせっかいなだけかもしれませんね(^^;;あんまりUIのことを考えていないアプリケーションって、エラーも何もなくどうしていいのかわからないものと、過剰にエラー表示が出るかどちらかというのが多いですよね。状況感知型が一番スマートなんでしょうけど、できたりできない理由がわからないというデメリットがあります…手間対効果から考えれば、何もしないのが一番簡単でしょうが…さて、みなさんはどれがよいでしょうか?

閑話休題。って、えらく長かったですが(^^;元の話は、えーと、何でしたっけ?(^^;;そうそう、移動のための一連の手順をもれなくダブりなくつくっていかなければなりません。別にこの一連の手順をひとつ作るくらいならそれ程問題はありません。では、軍団の移動を作るとどうなるでしょう。実は、基本は、軍団であっても武将の移動とまったく同じ手順で、ただ、武将でなく軍団の移動ということで書きつらねなければなりません。要は、武将絡みが軍団になっているというだけで、まったく同じ手順を2つ、書くわけです。もれはありませんが、完全にダブる内容を書くわけです。

まあ、2つくらいならコピペするなりして書いたりしていくわけですけども、攻め込む場合とか、撤退する場合とか、一部同じ一部違う内容をどんどかコピペして書いていくと、だんだん嫌になってくるわけですね(~_~;)だいたい武将の一覧表示とか城の一覧表示とかは、いろんな場面で使うわけですけども、同じ内容を次から次へとコピペで対応するのは、だんだん馬鹿らしくなってきます…私は(--;)だいたい、ひとつ直すと、他のあらゆるコピペ部分も直さないといけない、ということはよく言われます。それ以上に、たった1単語違う内容を書くために、全部分をコピペするなんて身の毛がよだちます(*_*)

そこで、どこでも使うような内容のものは、部品としてサブルーチン化するわけです。よくできたサブルーチンは、いろんな場面で対応できるもの、ですけども、場面によっては微妙に違いがあります。当然、同じなら同じルーチンで対応すればいいんですから、違いはあるんです。その違いを吸収せずに、このサブルーチンに入る前、出た後で、サブルーチン対応のための処理をしないといけない方法と、サブルーチン側でいろんな状況に応じるように対応する方法の2つがあります。サブルーチンの前後で処理する方法は、下手すればサブルーチンに行かず、そのままコピペして加工した方がいい、という場合もありましょうし、サブルーチンを少しでもいじれば、それを使っている処理すべてに影響が出るでしょう。こわいですねえ〜(x_x)

そうすると、できるだけサブルーチン側で違いを吸収してくれる方がいいわけです。ある状況なら前処理をこうして、後処理をこうして、とか、サブルーチン側で用意しておくわけです。これは、サブルーチンを使う側は楽ですけども、サブルーチン側は大変になります。どんな状況でももれなく対応できるようにしなければならないんですから、サブルーチンが肥大化します。リストなんてどこでも使うようなサブルーチンなんて、どんな些細な状況でも用意しなきゃならないわけですから、その組み合わせはだんだん気が遠くなって、そのうち嫌になってくるわけです。なんといっても、組み合わせが多すぎるとわけがわからないうえ、これまたちょっとでも直すとなると、影響がどこに及ぶか分からない。結局この危険がつきまとうのです。

最初はいいわけです。組み合わせ数も少ないので、(恣意的に)選んだ手順と似た手順は簡単に作れてしまいます。しかし、微妙に違うものからかなり違うものまで、組み合わせがだんだん複雑になってくるうえ、最初に(恣意的に選んで)作った手順に最適化されている可能性があり、他の手順では前処理後処理が大きく必要になる場合も出てきます。こうなると、一度他のものも含めて手直ししたくなるんですけども、手直しすると最初の(恣意的に選んだ)手順のところは、ほぼ確実に他の部分も手直しが必要になります。サブルーチンが、その部分用のものということで、変わる想定でつくられてないからです。で、我慢してそれを使うか、大幅作り直しになって、オブジェクト指向とかを勉強したくなるわけです(x_x)

でわ、オブジェクト指向ならこれが解消できるかというと、これまた簡単にはいきません(*_*)旧来型のオブジェクト指向の発想だと、オブジェクトとして、これまた恣意的に選んだ名詞となります。単純に、リスト、というオブジェクトができたとして、それがこれまでのサブルーチンと中身がそっくり同じだったら、問題は一向に解決されないわけです。かえってオブジェクト指向であるがゆえの見通しの悪さが加わるだけです。

手続指向では、サブルーチンにジャンプする以外は、順番に手続が流れていくわけですから、流れは比較的わかりやすいのです。これがサブルーチンだらけになったりするとオブジェクト指向と同様の見通しの悪さ、つまり、あっちへいったりこっちへ戻ったり、ということになってしまいますが…これがオブジェクト指向だと、サブルーチンだらけ、というイメージになります。つまり、より一層わけがわからなくなるんですけども、少なくとも、オブジェクトが適切な名詞だったりすると、まあ、なんとなく次が何をやっているかわかる、ということにはなります。

けれども、これで、オブジェクト指向ってこの程度?という気にはなるんですよね(~_~;)つまり、ちょっとかっこつけたサブルーチン?という程度では、まったく組み合わせ爆発には対応できていないわけなんですよ。武将か軍団かだけが違うとして、もっと楽に作れないものか?

で、デザインパターンになります(^-^)まさに、組み合わせ処理を意味するcaseとかswitchとかが出てきたら、デザインパターンを用意する、というように、こういった状況に対応するのがデザインパターンです。前回Factoryパターンは使いすぎはよくない、というお話をしましたけど、こういう、組み合わせの部分では抜群の効果を発揮します。まず、ほとんどのコマンドは手順としては似ているわけです。リストに何かを表示させて、そのうちひとつを選択させて、それに応じるコマンドを表示させて、コマンドを選択させ、実行する、という感じでしょうか。そういう外形部分をオブジェクトとして作るのです。リスト表示オブジェクト、左クリックオブジェクト、右クリックメニューオブジェクトという原型オブジェクトを作ります…といっても、中身はありません。リスト表示オブジェクトには、表示というメソッド、右クリ左クリにはそれぞれクリックというメソッドがある、と宣言するだけです。

そうして、具体的なオブジェクトを作ります。武将移動リスト表示オブジェクト、武将移動左クリックオブジェクト、武将移動右クリックメニューオブジェクトという感じでしょうか。で、具体的な中身をそれぞれに書きます。そうしておいて、オブジェクトを使う側では、その武将移動の各オブジェクトを生産するオブジェクト、武将移動Factoryオブジェクトを作り、リスト表示メソッドを実行するだけです。このFactoryオブジェクトの中身は、武将移動表示オブジェクト以下3種を作る、というだけです。ということは、オブジェクトを使う側は、それぞれ武将移動Factoryオブジェクトとか、軍団移動Factoryオブジェクトを作って、リスト表示メソッドを実行するだけで終わりです。

後は、左クリックする内容とか、右クリックメニュー内容とかはそれぞれ別々に書かれているわけですから、最初のFactoryオブジェクトの生産の組み合わせさえ間違えなければ、右クリックとかが同じ内容なら、同じものを生産すればいいわけです。組み合わせは最初にしてしまっているので、左クリックオブジェクトなどでは、その処理だけを考えておけばよいわけです。もちろん、ちょっとだけ違っていればちょっとだけ違う形で別のオブジェクトを作ればいいわけです。あんまりにも共通部分が多ければ、共通部分だけ取り出してオブジェクトの継承をすることも考えられますが、この発想で作られた各オブジェクトは非常に中身が小さいので、全部書いても、手続指向と違って、数行という程度なので、いちいち継承するより全部書いた方がまだましです。もしくは、全体の設計を考え直した方がよいかもしれませんね。

この、左右クリ&リスト表示各オブジェクトと、その組み合わせを生産するオブジェクトという組み合わせで、私の場合、ほとんどすべてのコマンドを表現できます。ある意味このパターンは、手続指向で手続を全部書くのと似ています。この状況ならこの組み合わせ、というサブルーチンの中の切り換え、switchがありませんので、ある流れを全部書いているのと同じですからね。つまり、他のことは考えなくてよいのです。そうでいながら、サブルーチンのメリット、同じ部分は共通化する、というメリットは受けています。それはオブジェクト指向だからです。クリック等各オブジェクトの中身で共通化できそうなところは全部、リストや武将オブジェクトといったところでまとめてしまってるからです。たとえば軍団に武将が参加するような手続も、「武将の軍団参加右クリックメニュー内オブジェクト」の中での表記は、「軍団.参加(対象武将,対象軍団)」(当然英語表記なので、gundan.sanka(taisyo,taisyogundan);とかになっていますが)というだけです。で、武将オブジェクトの参加メソッドでは、Tgundandata(taisyogundan).FkouseiinList.add(taisyo)と、一行書かれているだけだったりします。とはいえ、この別出しが重要で、おかげでどこの場面であっても、武将を軍団に参加させたければ、gundan.sanka(taisyo,taisyogundan)と書くだけで使えるのです。

このように、オブジェクト指向ではほとんど中身のない小型用途別オブジェクトもどんどん生産して消去し、ささいなことでも武将や軍団にかかわることは武将オブジェクトや軍団オブジェクトのメソッド(機能)として作っておけば、非常に見通しがよく、また、次から次へとどんどん組み合わせて作れるようになります。サブルーチン化が、できるだけ共通化部分をまとめる、という方向にあったのを、オブジェクト指向では、できるだけ細かい機能として別々に用意する、という、やってることは同じながら、内容が正反対という発想の転換ができれば、これほど楽なことはないのです。機能をばらばらに持たせることは、一見効率が悪そうながら、多少の違いで別に作るよりも、組み合わせの違いで表現した方が楽なのです。

たとえば、武将の移動を、所在する城の変更というだけのメソッドで作っておけば、軍団に所属する武将で、軍団が移動する際にもその武将の所在変更をそのメソッドが使えますし、ただの移動だけでなく、謀略中の者にも使えます。この辺はオブジェクト指向のメリットでもありますね。もちろん手続指向でも、サブルーチンの中身を細かくすればいいのですけど、そこまでするならオブジェクト指向と実体は変わらないし、他の処理も含めてオブジェクト指向の方が楽ですね。

で、先程の私のデザパタ、命令を工場セットで用意しておく、という方法で、どんどんコマンドが増殖中です。あまりに楽なので、何をコマンドとして用意するか、というところまできてしまいました(^^;;また、内政コマンド問題が勃発するのでしょうか…うむ!(~_~;)

index

〔TopPage〕

このページへのリンクはフリーです。
このページについてのご意見、ご質問などは、kr_ryo_green@yahoo.co.jpまでお願いします。
Copyright 2005© kr_ryo All rights reserved.
訪問件数