kr_ryo 徒然日誌 <2005年10月9日分>

三國志製作記116〜デザインパターンのこころ〜

こないだからトップページに掲載していますけど、「info@」ではじまるメアドは我がメールサーバであるYahoo!様のレベルでごみ箱送りになっています。一日何十通も届いているようなので、自衛のためには仕方がありません(~_~;)別段怪しげなサイトに登録したりだとかはしていない(^^;Aので、考えられるとしたら、ずいぶん以前に受信拒否の手続をしたせいか、この我が〔日曜プログラマーの部屋〕kr_ryo's HomePageにメアドを掲載しているせいか、でしょう。

気付くのがやや遅かったですが、今はこのサイトのメールアドレスは、平文ではなく、&#からはじまる16進数表記に変えています。この16進数表記、龐統の「龐」の字を外字を使わず表記できるように、結構便利な面もあり、また、スパムメール業者がサイトからロボットでメアドを収集する邪魔にもなるはず、です、が…多分、ロボットで収集できる収集できるなら、16進数表記にも対応できているような気もします。効果は上がっていないので、多分対応されているんでしょうねえ〜(ToT)

それと、旧のlivedoorメアドについては、我がサイトのメアドをYahoo!側のメアドに変えたとたん、スパムメールも極端に減っていたので、おそらくサイトからのメアド収集ロボットの仕業でしょう…!なんとも迷惑な話です(~_~;)それでもlivedoorは対応されていないながら、Yahoo!では、拒否メアド設定だけでなく送発信者のアドレス、タイトル、本文で、任意の文字が入っていればごみ箱送りにできますので、最初の「info@」ではじまるメアドは全部ごみ箱送りですo(^_-)Oこれでほとんどが消えます(^o^)v

さらに、こういうスパムメールはだいたいがサイトにアクセスさせるよう、本文にリンクを書いています。本文やタイトルや、メアドすら毎回変わっていても、クリックさせようとするサイトアドレスは変わらないことが多いので、たとえば「http://www.deaikei.com/」なら、「deaikei」でひっかけてごみ箱送りです。後はこの網を逃れたアドレスを登録することでなんとか平和を保っています。一日何千通ものスパムメールが届くといわれるMSビル・ゲーツ会長が、スパムメール対策を投げ出している以上、本格的な進攻を受ければ恐怖です。まさにサイバーテロ、技術革新が待たれます…

これに対し、携帯電話の迷惑メールも頻繁だったんですが、我がvodafoneの迷惑メールブロック機能が強力で、最近はまったく届かず平和になっています(^-^)一時はあまりの迷惑メールの多さにメール着信無反応にしていたくらいだったんですから…!

技術革新と技術悪用のいたちごっこ、そんな中、私もデザインパターンの研究共々、三國志製作の再開です。デザインパターンをわかりかけてきた、そんな時、まず再開とともにしたのは、これまで作ってきたコード(プログラム)の削除です(ToT)

当然のことながら、これまでのプログラムはデザインパターンに沿っていません。リストやボタンといったUIの見た目はそのままながら、ボタンをクリックして行う内容はこれまでの巨大武将オブジェクトや巨大城オブジェクトなどの中で扱ってきました。移動というコマンドに対応するオブジェクトは?武将でしょう。なら武将オブジェクトが、移動元移動先の城オブジェクトと連絡しあって移動という結果を実現すると考えてきました。そう考えるとされていたからです。

しかし、本来の意図と異なり、なんでもかんでも詰め込まれる巨大肥大オブジェクト、その上巨大オブジェクトがUIと直接やり取りするようになってくると、巨大メインルーチンからサブルーチンを切り離していく流れ、さらにメインルーチンを解体していく発想のオブジェクト指向本来の姿からも離れた、数本の巨大メインルーチン化が進んでいくように思えてきました。オブジェクト指向が小さく分けて分離して統治することを目指していたのに、巨大オブジェクトができてはいけないのです。

とはいえ、小さく小分けすればするほど、単なる機能別サブルーチンの集まりにすぎなくなります。そのうちオブジェクトの大群の前に、どのオブジェクトを使えばよいのかわからなくなるはずです…このルートもよくありません。もっともよいのは…?それこそデザインパターンであるはず、というお話でした。

とはいえ、『オブジェクト指向のこころ』を読んで理解をしなければ、自分で1から考え出すことはできません。たとえば最近MSエクセルなどについているマクロ=VBAを試してみようと思いました。しかし、プログラムに慣れているはずの私でも、その挙動、正しい書式などはわかりません。こういう形で書く、ということがあらかじめ決まっているのならば、その見本をいくつか見れば、今度はこれまでの経験がプラスに働き、簡単に書けるようになります。逆に、他の言語の経験が邪魔して、なぜこれが(こう書いて)できないの?という弊害もあります。その弊害を除くためにも、言語の習得というものは英語や日本語とかでも同じように、正しいものに慣れるのが先です。理屈ではありません。正しいものを知ればすむだけです。幸いネットで連続マクロ講座が掲載されていたので、数時間読めばわかるようになりました(^-^)後は、どれだけ「やりたいこと」を「できる機能」を見つけることができるか、です。

同じようにデザインパターンも、わからないながら、なんでこれがパターンとして重視されるのか、その意図をはっきり見極めなければなりません。やみくもに使っても、型にとらわれるだけでよくて無駄か、下手すれば弊害となる、とよく指摘されています。これまで問題となっていたのは、巨大オブジェクトの問題です。というのも、UIとの連絡や制御を含め、あらゆる機能が城や武将といったオブジェクトに放り込みすぎていました。これを解体するには、一番早いのは、実は、消して書き直すことです(ToT)書き換えは書き直しよりはるかに労力を要します。特にデザインパターンのような型にはまっていない書式は…!

せっかくだし、心機一転、巨大オブジェクトを全部消してすっきりしてしまいました(^^;A続いて問題となるのは、UI経由のユーザ制御系です。たとえば城ボタンを押せば城一覧、武将ボタンを押せば武将一覧を表示させるとします。表示させる対象が違うだけで、似たような内容です。ところが、表示させる対象が違えばプログラムも違います。手続指向型プログラムならば、違うところだけ別々に書いて、後はサブルーチンにまとめて切り出すところです。

オブジェクト指向ならばどうかというと、巨大オブジェクトの時期なら、城や武将といったオブジェクトに表示命令を飛ばし、それぞれ別々に(コピペしながら)プログラムするところでした。これは、機能はオブジェクトにするべきではなく、名詞であるオブジェクトの操作にする、という方法論によるものです。しかし、これだとサブルーチンの方が効率的に見えます。なんといっても同じ内容を別々の場所に書くのは無駄ですからね。けれども内容は、結局何かを表示するだけです。何か、というのが城か武将か、というだけにすぎないのです。それでも表示機能というものを別に取り出すと、オブジェクトというより単なるサブルーチンにしか見えません。

しかしデザインパターンを見ると、別に機能をオブジェクトとしてもよいように見えます。まさに正しいものを見なきゃわからない、というところでしょうか。とはいえ単純に機能の固まりをオブジェクトと言い換えたわけではありません。城の一覧表示を考えてみましょう。城ボタンを押せば、リストに城一覧が表示されるというものです。武将でもなく他国の城でもなく、自国の城を表示させるという内容です。そういう表示を行うという機能を持つもの、としてオブジェクトと考えます。その具体的な内容ごとに、細々オブジェクトを作っていくと、そのうちオブジェクトの山で何がなんだかわからなくなります。それが機能別オブジェクト切り出しの問題でしたね。

ではデザインパターンではどうするか。オブジェクトの生成に関して、何通りかのパターンがあります。そのうち私は当初FactoryMthodパターンを使っていて、途中でAbstractFactoryパターンを使ってみました。抽象的な工場です。なんのこっちゃいか?まず、最低4通りのオブジェクトが登場します。抽象的な工場、抽象的な製品、具体的な工場、具体的な製品です。ますますわけがわからなくなりますね(^^;Aこのうち、先程の自国城一覧を表示する、という実際の部分は具体的な製品となります。これで、機能という動詞ではなく、製品という名詞になりましたね…って、そんなことは単なる言葉のごまかしにすぎません(^^;Aとはいえ、4つが協同すれば、うまくオブジェクト指向的になります。では、残り3つはなんのためにあるのか。

手続指向型プログラムとオブジェクト指向プログラムの最大の違いは、手続指向型がプログラムを順番に順番に進めていくのに対し、オブジェクト指向はオブジェクトの中では順番に進めるといえど、どれかのオブジェクトに命令を与えて動かすまでは止まっているのです。だから、手続指向型では次はどこにいくのか必ず決めていなければならない(決めていなければ次の行に進むだけ)のに対し、オブジェクト指向では、次にどこにいくかは必ずしも決まっていないのです。どこに行くか決まってなければ、次に何が起こるかははっきりとはわかりません。けれども、準備されていればいつでもどこでも使えるというメリットがあるのです。とはいえ、そんなオブジェクトは、最初にまず準備、生成しなければなりません。手続指向型では順番どおりに進むから、順番どおりに命令を並べればいいんですけど、オブジェクト指向ではプログラム開始後どこかでオブジェクトを実体化させなければなりません。その実体化したオブジェクトに命令を与えるのです。

実体化させたオブジェクトは、消すまで残ったままです。下手なプログラムでは(いや、プロですら)オブジェクトを消し忘れて、プログラムが終わってもずーっとオブジェクトがメモリ上に残ったまま、ということもありえます(いわゆるメモリリーク)。それくらいオブジェクトは独立しているのです。そこまで独立しているから、一度作れば、任意の時点でそのオブジェクトを使うことができるのです。

ここでたとえ話に入ります。たとえば、テレビリモコンがそばにあればすぐチャンネルを変えられますね。リモコンがなければ、いちいちテレビのそばまで行って、何度かボタンを押して、で、戻って寝っころがる、ということをしなければなりません。気に入らなければまたその繰り返しです。オブジェクト指向でプログラムを作るのは、リモコンでチャンネルを変えるのと似たような感覚になります。で、そのリモコンがオブジェクトと考えてもいいわけです。

ところが、そのリモコンをまず手元に取っておくように、オブジェクトも使うためにはまずは生成しなければなりません。最近ではどれもひとつで操作できるものもあるとはいえ、ビデオのリモコン、ステレオのリモコン、クーラーのリモコンと、リモコンはリモコンでもいっぱいありますよね。けれども、リモコンを取ってくる、という動作は変わりませんし、いろいろ機能がものによって違うとはいえ、リモコンを使って何かする、という使う、ということは同じでしょう。この、リモコンを取ってくる、という動作をすることが抽象的な工場オブジェクトの役目、リモコンを使う、ということをすることが抽象的な製品オブジェクトの役目、といえばわかりますでしょうか。で、具体的な工場オブジェクトとは、それぞれのリモコンを取ってくること、再生とか温度を下げるとかいろいろな機能を実行する機能を使えるようにする、ということが、具体的な製品オブジェクトといってもよいでしょう。これで4つ登場です。

要するに、リモコンを取る、リモコンを使う、ということが抽象的、ということで、それによって音楽を流したりテレビを付けたりすることが具体的ということです。理屈ではわかりますが、なんで4つのオブジェクトに分けなきゃならないのか、そこが問題です。もちろん分けなきゃ巨大オブジェクトができる、ということになります。コマ送り再生から衛星51チャンネルまで全部ボタンの揃った巨大リモコンは、まあ、考えられなくもないですが、操作も邪魔くさそうならば、でかくて邪魔になりそうです。巨大オブジェクトの弊害はそれと似ていますね。

とはいえ、操作する人も、製品ごとにリモコンがあるということはこれまた邪魔なわけです。テレビ、ビデオ、ステレオ、エアコン、これでもう4つです。けれども分けておけば、必要なものだけ用意しておけば済むわけですね。で、リモコンの主な用途は、スイッチを入れるのと、チャンネルや音量や頭出しや温度など、状態設定を変えることです。それも、付ける、変える、ということの認識くらいで、温度と音量の変更の具体的な違いを厳密に考えたりしてはいないはずです。変えれるものを変えてるだけです。そういう意味では、統合型巨大リモコンにおいても、スイッチを共通化して、音量や温度を変えるボタンも共通化してもいいわけです。これで個別のボタンが多少減りますね。これが抽象化というものです。

ただ、それでも、変えるボタンやスイッチは、どれに向けて行っているのかはわかりません。使っている人が何をしたいのかは、対象がはっきりしないとわからない面もあります。同じ方向にエアコンとテレビがあって、上げるボタンを押したとたん、温度が上がり、音量も上がったりするのは問題です。つまり、使う方にとっては、音量を3とか温度を2度とかいう具体的な内容より、上げたい下げたい、という抽象的な思いを伝えるだけの方が楽ではあるんですが、逆に、使われる方にとっては、そもそも自分が対象であるのかどうか、いったいどれくらい変えればいいのかはっきりしてもらわないと困るのです。

そこで、使う人にはそれぞれのリモコンを取ってきてもらう、後はスイッチを入れたり、温度もしくは音量を上げたり下げたりしてもらう、という方が一番よいパターンです。いくら統合型リモコンといえど、だいたいテレビとビデオどまりで、エアコンまで統合してもらいたいとはあんまり思わないはずです…あんまりリモコンが多ければ思うこともあるでしょうが(^^;Aそれと似たような発想がデザインパターンのファクトリーパターンなのです。先程では工場といってましたが、抽象的なリモコンを取ること、具体的なリモコンを取ること、抽象的なリモコンの操作、具体的なリモコンの操作、といってもいいわけです。使う人にとっては、どれに対しても使える抽象的なリモコンの方が、なんも考えなくていいだけ楽なのです。わざわざ統合型リモコンを買う人がいたり、リモコンが増えて困ったりする人がいたりするのはそのためです。とはいえ、リモコン操作される側にとっては、誰がどのように操作されるのかはっきりしてもらわないと困るのです。製品ごとの個別リモコンがあるのはそのためです。そしてボタンも使い方も製品ごとに違います。

これでオブジェクトが4つ登場する理由が出てきました。個別のリモコンを取るのと同じように、オブジェクトを作るためのオブジェクトを作る必要がまずあります。その段階では、個別のこの具体のリモコンを取ったよ、という動作、この具体のオブジェクトを作るよ、という命令が必要です。しかし、使う人にとっては、リモコンを「取る」ということは同じわけですから、「この」リモコンを取る、という「この」以外は同じでもいいわけです。そこが抽象的な工場(リモコン取得)オブジェクトと、具体的な工場(リモコン取得)を分ける理由です。抽象的な工場はひとつでいいものの、具体的な工場は作る製品ごとに異ならせます。で、少なくとも使う人は、はっきりさせるのは「この」だけで、後は共通化(取る)が望ましいわけです。これで何かのリモコンを手元に引き寄せ、何かのオブジェクトを生成することができました。

リモコンを使う際も、スイッチを入れる、チャンネルや冷房暖房を変えたい、音量や温度を変えたい、という、変えたい、ということはずいぶん共通化できます。この共通化こそ抽象化とほぼイコールなんですけど、微妙に違います。抽象化では具体的な面を捨て去ってしまうことによってしまうのです。変更、というだけでは、同じテレビでもチャンネルなのか音量なのかわかりません。上昇、ならまだしも、それでもチャンネルの繰り上がりなのかどうか怪しい面があります。いずれにせよ、使う人及び使われる人が区別できる範囲で抽象化した操作ができる方が望ましいのです。それが抽象的な製品(リモコン操作)です。もちろん、操作すればどうなるかをはっきり決めるのが具体的な製品(リモコン操作)です。使う人は変えたい、というだけで済みますが、使われる方は、チャンネルなのか音量なのか温度なのかをはっきりしてもらう必要があります。どうやってはっきりするのか、それは先程オブジェクトを作ってくれた具体的な工場が何を作ったか、具体的などのリモコンを取ってきたかによります。取ってきたリモコンさえ具体的にテレビのものならば、スイッチを入れる、という操作は、いくら抽象的な、ただ、オン、という操作だけであっても、テレビがつきます。しかし、つける操作の中身はテレビとビデオですらおそらく全然別でしょう。

ということで、ようやく4つに分けた意味がはっきりします(^^;Aプログラムを使う側からは抽象的に、使われる側からは具体的にというアプローチです。それによって、使われる側の方をどういじろうとどう変更しようと、使い方のつながりさえ変えていなければ、使う側からはなんにも変わったようには見えないのに、中身を変えることができるのです。ということは、再利用しやすいことにつながります。デザインパターンの第一のメリットはここです。再利用しやすくしているのです。再利用するためには、使う側との接点は少ない方がよいわけでして、そのために抽象的オブジェクトと具体的オブジェクトの2層制がよく取られるのです。具体部分を変えても、抽象部分、つまり外からの見た目の部分は同じになるからです。

ここまでわかればデザインパターンのとりあえずの意味がわかります。武将なのか城なのかは別ながら、表示の仕方によって具体的な製品オブジェクトを変えて、具体的な工場オブジェクトから作り、使う側のUIのプログラム部分では、抽象的な製品オブジェクトで操作する、という感じで、使う方を作る場面ではずいぶん楽ができそう、なのですよ…(^o^)

index

〔TopPage〕

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