もどるの。

@ど素人によるオブジェクト指向入門♪

2001/06/03
んで。
ぷろぐらみんぐがテーマだとはいっても、
やはりそれなりに設計しておかないとだめなの。

さきほどの定義によれば、機能要求者、業務精通者、OO技術者、
がそろっていないと良い設計はできないの。

今回は全部みゅがやっているのでその前提は満たしたことにして(笑)、
以下のようなドキュメントが作成されたの♪



こんな図のことをクラス図と呼ぶの。
ここで登場してくる四角ひとつひとつがオブジェクトなの。
RDB上はこのオブジェクトひとつがひとつのテーブルなの。

で。四角のなかがさらに3つの四角になっているの。
一番上がそのオブジェクトの名前なの。
この名前は非常に重要で、別の人が見たときに
直感的に何を表した物なのか判別できないといけないの。
ここでは4種類登場しているの。
「Player」投球者。プレーヤーなの。
「Game」ボーリングの1ゲームなの。
「Frame」ボーリングの1フレームなの。
「Race」開催日なの。
Player、Game、FrameはともかくRaceで開催日を連想できるか謎なの(涙)。
だって開催を表現する適当な英単語がわからなかったんだもの(涙)。
そんなわけでこれは悪い例なの。

で。
真ん中の四角がそれぞれのオブジェクトが持つ属性なの。
RDB上では各テーブルの項目になるの。
厳密にいえばこの図からでもきちんとキー項目がどれか
わからないといけないんだけど今回は省略(涙)。
やっぱり悪い例なの。
で、まあ、どんなものが属性なのかというと、
それぞれのオブジェクトの特性を表すものなの。
PlayerはName=名前を持っているの。
RaceはYMD=開催日を持っているの。
当然この属性も見ただけでなにを表すものなのか直感的に
分からないといけないの。
だからYMDという名前の付け方はどうかなぁ(涙)。
GameはID、YMD、GameNoをもっていて、
どのプレイヤーがいつの開催で何ゲーム目に行ったものなのかがわかるの。
その属性はScore=成績をもっているの。

ちなみにどのオブジェクトがどんな項目をもつのか、
というのは非常に重要なの。
実はこのGameの属性にScoreをもたせるのは本来の分析からいえば
不正解なの。
なぜならGameのスコアは、
そのゲームの中に存在する各フレームのスコアを合計したもので
計算することができるの。
このような項目は導出項目とよび、本来は属性値にするべきではないの。
でも今回のシステムは集計、解析型なので、
後々SQL文一発でも解析できるようにわざともたせたの。
ほんとは悪い例なの。
でもあとでソース見てもらえれば分かるけど、
プログラム内ではGameオブジェクトにはScore属性はもたせていないの。

で。
各オブジェクトを表す四角の中にある一番下の四角が
各オブジェクトの振る舞いを表しているの。
各オブジェクトが一体どんなことができるのかを表しているの。

PlayerはgetStrikeCount()という振る舞いをもっているの。
ちなみにこの振る舞いのことをメソッドと呼ぶの。
このメソッドの名前もとても重要なの。
くどいようだけれども直感的に理解できる名前をつけないといけないの。
getStrikeCount()はストライクの数を数えるメソッドなの。
Playerは自分のストライクの数を答えることができるの。

でもよくみてみるとGameにもgetStrikeCount()がいるの。
これも名前が一緒だから同じことをするの。
でも、GameのgetStrikeCount()は
そのゲームで出たストライクの数を数えるメソッドなの。

同様にFrameのgetStrikeCount()は
そのフレーム内でのストライク数を数えることができるの。

さらにFrameにはgetScore()とgetScore( ThrowNo )という
同じ名前のメソッドが存在しているの。
違いは()の中が空っぽかThrowNoと書いてあるかなの。
getScore()はそのフレームのスコアをもどすの。
そのフレームがスペアだったら次のフレームの1投目の点数を
加えた点数を戻さないといけないの。
それに対してgetScore( ThrowNo )はそのフレームの何投目のスコアが
欲しいのか指定してあげると単純に何ピン倒したのかを
答えることができるの。
でもどちらもスコアを答えるという意味では同じなの。
だから同じ名前なの。
これはポリモフィズム=多相性と呼ばれる考え方なの。

それからメソッドにはこの図では省略しているんだけど、
それぞれの属性を取り出すための、
getName()とかgetYMD()とかgetGameNo()とかが存在しているの。
各オブジェクトは他のオブジェクトの属性に直接アクセスしてはいけないの。
これをカプセル化というの。

オブジェクト指向ではカプセル化の概念は極めて重要なの。
オブジェクト指向が高生産性であるといわれる理由の
その一翼を担っているの。

今回のボーリングなんかはそのルールが変わることはおそらく
ないだろうけれども、実際のビジネスシステムの場合は、
そのビジネスルールが変わることは容易に想像できるの。
たとえばある日突然、スペアをとったフレームのスコアは、
次のフレームの1投目の点数を足すのではなく、
固定で16点とする、なんてルールができたとするの。

もしカプセル化がまもられておらず、
フレームのスコアを必要とする処理全ての場所で、
「次の1投目の点数を足す」というコーディングがされている場合、
すべての箇所を「16点とする」と書き換えなければならないの。

でもカプセル化によりフレームのスコアは必ず
Frame::getScore()から取り出していたらどうかしら?
おそらくgetScore()の中では「次の1投目を足す」という
コーディングが書かれているだろうから
これは修正しなきゃいけないけれども、
実際にそれを使って処理を行っている部分は
「getScore()を利用する」というコーディングに変化は生じないので
プログラムの各所を何カ所も直す必要はないの。

またプログラムの作成時でも同様で、
重要な処理はその処理を管理すべきオブジェクトのメソッドとして
定義しておけば、そのメソッドを利用したいところでは
メソッドを呼び出すという1ステップから数ステップの
コーディングを記述するだけで済んでしまうの。
もちろんその分生産性の向上に寄与できるの。

ってそれってサブルーチンと一緒じゃん。
とおもった人はするどいの。
メソッドとサブルーチンは似ているの。
だからOOプログラミングをしていなくても
優秀なプログラマは必ず適切なサブルーチンを作成しているの。
適切な。
多すぎず、少なすぎず、そしてわかりやすく。

下手なプログラマが作ったサブルーチンはもう意味不明(涙)。
なにをする処理かわからない。
どこから呼び出すべきなのかわからない。
似たようなルーチンがいくつも作成されている。
どうやって使い分けるのかわからない。
しかもコピー&ペーストでつくってあるから
一カ所直すときに何カ所も修正しないといけない(涙)。
しかもそういう人は特にドキュメントもなにも残していない(涙)。
わずかな手がかりのプログラム内コメントは
「 c = a + b; //ここでAとBを足す」みたいに
コード読んだらわかるようなことしか書いてない(涙)。
その「a」が何を意味していて、「b」が何を意味するのか、
その和である「c」が何を意味するのか。
これが重要なのに(涙)。

まあ、みゅもそんな偉そうなことはいえないけど・・・。

で。
オブジェクト指向設計においては、
サブルーチンに相当するメソッドもちゃんと分析時に設計しておくの。
そしてメソッドの役割、
つまりどんな処理を行うサブルーチンなのか、ということも。

そしてこれらのメソッドは全体の処理をこなすうえで
重要な意味を持っているはずなの。
そうでなければメソッドとして定義されないもの。

その結果わかりやすく簡潔なプログラミングがおこなわれて、
だからバグも少なくなるし、
後からの仕様変更にも強い、高品質なシステムが作成されるの。


つづきはさくせいちゅう♪