Skip to content

Latest commit

 

History

History
630 lines (413 loc) · 33.3 KB

tut_uml_modeling_bs02.adoc

File metadata and controls

630 lines (413 loc) · 33.3 KB

スコアシートの構造を調べる

ボウリングのゲームスコアを記録するスコアシートは、どのような要素で構成されているでしょうか。 また、それらの構成要素の間にはどのような関係があるのでしょうか。 構成要素や構成要素の関係を表すには「構造のモデル」を使います。 構造のモデルを使って、スコアシートの構成要素や、構成要素間の関係を検討してみましょう。

Note

このチュートリアルでは、クラッシックスコアリング( [classic_scoring] )の場合について考えることにします。

スコアシートの例

ゲーム中のスコアシートの例を スコアシートの例 に示します。 この例では、2人でプレーしています。 いまは、2ゲーム目のプレー中で、1人目の6フレーム目の第1投目までゲームが進んでいます。 また、彼らは1フレームずつ交代で投球していることがわかります。 もし、彼らがもう1ゲーム分プレーする場合には、このスコアの下にもう一度2人分のスコアが追加されるでしょう。

{full-width}
Figure 1. スコアシートの例
Note

ボウリングでは、「ゲーム」が、各自が10フレーム分プレーした結果を指す場合と、複数名で10フレーム分プレーしたひと組の結果を指す場合があるようです。 これらを呼び分ける方法がわからなかったので、このチュートリアルでは、前者を「スコア」、後者を「ゲーム」と呼ぶことにします。

実際のボウリング競技において、これらの呼び分方をご存じの方は、その呼び分け方を使うとよいでしょう。

スコアシートを観察してわかることをまとめました。

スコアシートを観察してわかること(決めたこと)
  • スコアシートには、プレー開始日時が記載されている。

  • スコアシートには、プレーヤー名とその人の10フレーム分の投球を記録する欄がある。

    • これを 「スコア」 と呼ぶことにする。

  • 1つのゲームの進行中は、1フレームごとにプレーヤーが交代して投球する。

    • この方式は 「ベーカー方式」 と呼ばれている。

  • スコアシートには、複数人のスコアが記録されている。

    • 同時に進行している複数名のスコアのまとまりを 「ゲーム」 と呼ぶことにする。

  • プレーヤーの組を単位として複数回ゲームをプレーできる。

これらを元に、スコアシートの構成要素や構成要素の間の関係をモデル図で表してみましょう。

スコアシートの構造をオブジェクト図で表す

スコアシートの構造を調べるには、まず実際のスコアシートがどうなっているかを調べるのがよいでしょう。 スコアシートに記入されている具体的なデータを使って図を作成するには、オブジェクト図が向いています。

それでは、スコアシートの例を参照しながら、スコアシートのオブジェクト図を作成してみましょう。

プロジェクトに設計モデルを追加する

まず、 {astah} で作成したプロジェクトに設計モデルを追加しましょう。

Tip

「設計モデル」ということばが表すものは、開発に使用する手法や分野によって少しずつ異なっています。このチュートリアルでは、次の2つの側面について表したものを設計モデルと呼ぶことにします。

  • 対象とする業務やサービスに必要となる構成要素やその関係を「構造のモデル」(静的モデル)として表したもの。

  • 業務やサービスを実現するために必要となる動作を「振る舞いのモデル」(動的モデル)として表したもの。

設計に関わる構成要素は、対象とする業務やサービスを分析して得られることもあれば、開発に採用する資源や方式から得られることもあります。

プロジェクトに設計モデルを追加する
  • 構造ツリー上で、プロジェクトを選択する。

  • 右クリックしてポップアップメニューを開き、「モデルの追加>モデル」を選択する( プロジェクトにモデルを追加した )。

{three-quarters-width}
Figure 2. プロジェクトにモデルを追加した
追加したモデルに名前をつける
  • 構造ツリー上で、追加したモデルを選択した状態で、プロパティーの「ベース」タブを選択する。

  • 「名前」を編集して「設計モデル」とする( モデルに設計用のモデルとして名前をつけた )。

  • 入力が確定すると、構造ツリーの表示にも反映される。

{three-quarters-width}
Figure 3. モデルに設計用のモデルとして名前をつけた

設計モデルにオブジェクト図を追加する

「オブジェクト図(インスタンス図と呼ぶこともあります)」を使ってスコアシートに登場するオブジェクトを表してみましょう。 {astah} でオブジェクト図を作成するときは、「クラス図」を使います。

それでは、プロジェクトにクラス図を追加して、オブジェクト図を描いてみましょう。

設計モデルにオブジェクト図を追加する

まず、プロジェクトにオブジェクト図を描くのに使うクラス図を追加します。

  1. 構造ツリーから設計モデルを選択し、右クリックしてポップアップメニューを開く( モデルにクラス図を追加する )。

  2. 「図の追加>クラス図」でクラス図が追加される。

{three-quarters-width}
Figure 4. モデルにクラス図を追加する
オブジェクト図に名前をつける

追加したオブジェクト図に、図の名前を設定します。 描こうとしているのはオブジェクト図ですので、それがわかるような名前をつけます。

{three-quarters-width}
Figure 5. 図の名前を「ゲームスコアのオブジェクト図」にする

オブジェクト図にスコアシートを追加する

スコアシートの例 や「スコアシートを観察してわかること(決めたこと) 」を観察しながら、スコアシートに記載されている要素をオブジェクト図に追加してみましょう。 まず、「スコアシート」オブジェクトを追加します。

スコアシートを表すオブジェクトを追加する

こんどは、図にスコアシートを表すオブジェクトを追加してみましょう。

  • パレットから「インスタンス仕様」を選択して、図に配置する( インスタンス仕様を追加する )。

  • 「インスタンス仕様0」という名前のオブジェクトが配置される(末尾の数字は作るたびに新しいものに変わる)。

{three-quarters-width}
Figure 6. インスタンス仕様を追加する
オブジェクト名を個別のスコアシート名に変える

実際のスコアシートでは、個々のスコアシートを区別するようなはっきりとした名前はついていないこともあるでしょう。スコアシート番号みたいな通番をつけている場合もあるかもしれません。

ここでは、追加したオブジェクトが特定のスコアシートを表すことがわかるよう、他のシートと区別できるような名前(オブジェクト名)をつけましょう。

  • 追加したオブジェクトを選択し、プロパティーから名前の編集欄を選択する( 名前を「scoresheet01」に変更する )。

  • オブジェクトの名前に、 スコアシートの例 のスコアシートを示す固有の入力する。ここでは「scoresheet01」とした。

  • オブジェクトの名前の入力を確定すると、ダイアグラムエディタ中のオブジェクトの名前にも反映される。

{three-quarters-width
Figure 7. 名前を「scoresheet01」に変更する
Tip
個々のオブジェクトを識別するためにつける名前のことを、オブジェクト名(またはインスタンス名)と呼びます。

スコアシートオブジェクトにクラスを割り当てる

追加したオブジェクトは、名前はつけたものの、たくさんあるスコアシートの仲間であるとみなす方法がありません。 それは、このオブジェクトがどんなクラスに属するか決まっていないからです。 それが分かるよう「スコアシート」を表すクラスを定義して割り当てておきましょう。

スコアシートクラスを追加してオブジェクトに割り当てる

まず、図中のオブジェクトに割り当てるクラスを用意します。

{three-quarters-width}
Figure 8. オブジェクトを選択してクラスを「新規作成」する
{half-width}
Figure 9. クラス「ScoreSheet」を定義する
スコアシートに属性を追加する

スコアシートクラスがどのような情報を保持するのかはまだ検討が必要ですが、ひとますプレー開始日時を保持することは必要そうです。 そこで、プレー開始日時を表す属性を追加しましょう。 ここでは、プレー開始日時を表す属性の名前を「play_date」とします。

  • スコアシートクラスの「属性」タブを選択する。

  • 「+」ボタンを押すと属性が追加されるので、名前に「play_date」を入力する( 属性「play_date」を追加する )。

{half-width}
Figure 10. 属性「play_date」を追加する
追加した属性の型を定義する

追加した属性も、どんな型なのかを設定しておきましょう。 プレー開始日時を表す属性の型の名前を「Time」とします。

Note
「Time」は、Rubyのクラスライブラリのクラスのひとつで、日付と時刻を操作するためのクラスです。このクラスに対応づけする見込みで割当ててみます。
  • 追加した属性の「型」欄を選択する。

  • 「型」欄を編集状態にして「Time」を入力すると、ダイアログに「型になるTimeを新規作成しますか?」というメッセージが表示される( クラス「Time」の追加を促すダイアログ )。

  • 「はい」をクリックしてダイアログを閉じる。

  • クラス「Time」が作成される。( クラス「Time」が追加された )。

  • 構造ツリーにも追加されたことを確認する。

{half-width}
Figure 11. クラス「Time」の追加を促すダイアログ
{half-width}
Figure 12. クラス「Time」が追加された
オブジェクト図や構造ツリーを確認する

オブジェクト図においても、構造ツリーにおいても、追加したオブジェクトの名前が変わっているを確認します。

  • 「閉じる」をクリックして、クラス定義のダイアログを閉じる。

  • オブジェクトの表示が「scoresheet01 : ScoreSheet」に変わっている。

  • 属性「play_date」の属性値を保持する欄(スロットと呼ぶ)も追加されている。

  • 構造ツリーにもTimeクラスが追加されている( オブジェクトにクラスやスロットが割当てられた )。

{full-width}
Figure 13. オブジェクトにクラスやスロットが割当てられた
追加したスロットに属性値を設定する

追加した属性「play_date」のインスタンス(スロットと呼びます)に、属性値として具体的な日付データを設定します。

{full-width}
Figure 14. オブジェクトのスロットに属性値が追加された

オブジェクト図にゲームを追加する

次に、「スコアシート」を追加したのと同じ手順で「ゲーム」オブジェクトを追加します。 スコアシートの例 の場合ゲームが2組あるので、ゲームのオブジェクトを「game01」、「game02」としましょう。 クラス名は「Game」としましょう。

ゲームを表すオブジェクトを追加する

最初の(1組目の)ゲームを追加してみましょう。

{full-width}
Figure 15. ゲームを表すオブジェクト「game01」とクラス「Game」を追加した
次のゲームのオブジェクトを追加する

次のゲーム(つまり、2組目)のオブジェクトも追加してみましょう。

{full-width}
Figure 16. ゲームを表すオブジェクトを追加し、既存のクラスを割当てた

オブジェクト図にスコアを追加する

こんどは、プレーヤーひとり分のスコアを記録しているスコア部分を追加しましょう。 スコアシートの例 の場合、スコアは4つあります。

このチュートリアルでは、プレーヤー名はスコアの属性と考えることにしておきます。 (もちろん、プレーヤーを独立したクラスと考え、複数のスコアとを関連づけた方がもっとよいでしょう)

それぞれのプレーヤーのスコアを表すオブジェクトを追加する

それぞれのプレーヤーごとにスコアがありますので、まず、プレーヤーごとのスコアのオブジェクトを追加します。

{full-width}
Figure 17. スコアを表すオブジェクト「score01」を追加した
{half-width}
Figure 18. 属性「Player」を追加し、クラス「String」を追加して割当てる。
追加したオブジェクトのスロットに値を設定する

追加したオブジェクトの「player」スロット(スコアクラスの属性playerの、このオブジェクトにおける属性値)を設定します。

{full-width}
Figure 19. 「player」のスロットの値にプレーヤー名を設定した
{full-width}
Figure 20. 残りのスコアのオブジェクトを作成した

オブジェクト図にフレームを追加する

次に、各スコアに記載されているフレームを追加しましょう。 やはり、スコアシートの例 や「スコアシートを観察してわかること(決めたこと) 」を観察しながら、作成します。 ですが、フレームのオブジェクトの数が多いので、この場で作成してみるのは一部だけにします。

それぞれのスコアのフレームを表すオブジェクトを追加する

それぞれのスコアは、フレームを持っていますので、これを表すオブジェクトを追加します。

  • パレットから「インスタンス仕様」を選択して図に配置して「frame0101」とする。

  • 「Frame」クラスを追加して、「frame0101」に割当てる( フレームを表すオブジェクト「frame0101」を追加した )。

  • 「Frame」クラスの属性に「frame_no」、「first」、「second」、「spare_bonus」、「strike_bonus」、「total」を追加する。

{full-width}
Figure 21. フレームを表すオブジェクト「frame0101」を追加した
追加したオブジェクトのスロットに値を設定する

オブジェクト「frame0101」の各スロットに値を設定します。

{full-width}
Figure 22. オブジェクト「frame0101」の各スロットの値を設定した
{full-width}
Figure 23. 残りのフレームのオブジェクトを作成した(一部だけ)

オブジェクトのつながりを整理する

オブジェクト図に、スコアシート、ゲーム、スコアのオブジェクトが追加できました。 スコアシートの例 を見ながら、これらの間にはどのようなつながりがあるか考えてみましょう。

オブジェクト同士のつながりを考える
  • スコアシートは複数のゲームを記録できるので、スコアシートとゲームにはつながりがありそうです。

  • ゲームでは、複数のプレーヤーのスコアを記録するので、ゲームとスコアにはつながりがありそうです。

  • スコアにはフレームごとのピン数などを記録するので、スコアとフレームにはつながりがありそうです。

つながりがありそうなオブジェクトをリンクを引いてつないでみましょう。

オブジェクト図では、オブジェクト間のつながりを表すには、「リンク」と呼ぶ線でつないで表します。 これは、クラス図におけるクラス間のつながりを表す「関連」のインスタンスにあたるものです(クラス図は、オブジェクト図を元に作成します)。

まず、スコアシートとゲームの間にリンクを引きましょう。

作成したオブジェクトの間にリンクを引く

まず、「scoresheet01」から「game01」へリンクを引いてみましょう。

{full-width}
Figure 24. リンクの引き始めのオブジェクトで青枠を表示させる
{full-width}
Figure 25. 青枠が表示されたらマウスのボタンを押したままマウスカーソルをドラッグする
{full-width}
Figure 26. リンク先のオブジェクトにも青枠が表示されたらマウスのボタンを離す
ほかのオブジェクトの間にもリンクを引く

「game02」へも 作成したオブジェクトの間にリンクを引く と同様の手順でリンクを引きましょう( ゲームからスコアへリンクを引く )。

  • 1ゲーム目のスコアは、1つ目のゲームにリンクを引く。

  • 2ゲーム目のスコアは、1つ目のゲームにリンクを引く。

{full-width}
Figure 27. ゲームからスコアへリンクを引く
{full-width}
Figure 28. 残りのつながりについてリンクを引く

これで、 スコアシートの例 の要素を反映したオブジェクト図が作成できました。

スコアシートの構造をクラス図で表す

スコアシートの構造をオブジェクト図で表す 」では、実際のスコアシートがどうなっているかを調べるために、スコアシートに記載された内容を使ってオブジェクト図を作成しました。 しかし、特定のスコアを記載した図では、プログラムで扱うような、より一般的なスコアシートを扱えません。 代わりに、オブジェクト図の作成時に考えたクラスを使って、クラス図を使います。 そこで、作成したオブジェクト図 残りのつながりについてリンクを引く を元に、ゲームスコアのクラス図を作成してみましょう。

クラス図とスコアシートクラスを追加する

設計モデルに、「ゲームスコアのクラス図」と「スコアシートクラス」を追加しましょう。

スコアシートのクラス図を追加する

まず、「ゲームスコアのクラス図」を追加します。

  • 構造ツリーで、「設計モデル」でポップアップメニューを開き、「図の追加>クラス図」でモデルにクラス図を追加する( モデルにクラス図を追加する )。

{half-width}
Figure 29. モデルにクラス図を追加する
{half-width}
Figure 30. 追加した図を「ゲームスコアのクラス図」とした
クラス図にクラスを追加する

追加したクラス図に、ゲームスコアクラスを追加します。

{full-width}
Figure 31. 既存のクラスを構造ツリーからクラス図に追加する

クラス間の関連を追加する(1)

作成したオブジェクト図( ゲームからスコアへリンクを引く )に記載されているリンクを参照して、リンクでつながっているオブジェクトが属するクラスの間に関連を引きます。

スコアシートとゲームの間に関連を追加する

まず、「ScoreSheet」クラスから「Game」クラスへ関連を引きます。

{three-quarters-width}
Figure 32. 「ScoreSheet」クラスから「Game」クラスへ関連を引いた
スコアシートからみたゲームの多重度を設定する

スコアシートには1ゲーム以上の複数のゲームを記録できます。 クラス間の関連において、このことを表には多重度を使います。

{half-width}
Figure 33. 「ScoreSheet」からみた「Game」の多重度を「 1..* 」に設定した
スコアシートからみたゲームの関連端名を設定する

スコアシートがゲームを参照するときに使う名前を決めるために、関連端名を設定します。

{half-width}
Figure 34. 「ScoreSheet」からみた「Game」の関連端名を「games」に設定した
スコアシートとゲームの集約関係を設定する

スコアシートには、複数のゲームを追加できます。 このことをクラス図に反映する方法がほしいところです。

まず、スコアシートが複数のゲームをとりまとめていること表すのに、「スコアシートには複数のゲームを集約する」役割があるというように捉えてみましょう。 このような役割を表すために、クラスの関連端には「集約」を表すための記法が用意されています。

さらに、同じスコアシートで追加でゲームをやりたいときは、新しいゲームを始めた時点で新しいゲームの記録を始めます。 つまり、スコアシートが作成される時点と、あるゲームが開始される時点が同時とは限らないわけです。 このように、集約する側(ここではスコアシート)のインスタンスと、集約される側(ここではゲーム)のインスタンスが作成される時点が同じではないことを「スコアシートとゲームはライフサイクルが異なる」といいます。 一方で、集約する側とされる側が同時に作成され、同時に破棄されるなら、「ライフサイクルが同じ」と考えます。 集約の記法には、ライフサイクルが異なる場合の「aggregate」、ライフサイクルが同じ場合の「composit」を表すオプションが用意されています。

ここでは、スコアシートが複数のゲームをとりまとめていて、スコアシートとゲームのライフサイクルが異なることを反映して、スコアシート側の関連端に「aggregate」オプションを指定した集約を設定しましょう。

{half-width}
Figure 35. 「ScoreSheet」が「Game」を集約していることを示した
{three-quarters-width}
Figure 36. 「ScoreSheet」から「Game」への関連が引けた

クラス間の関連を追加する(2)

ゲームとスコア、スコアとフレームの間にも関連を引いて、関連端も設定してみましょう。

ゲームとスコアの間に関連を追加する

こんどは、「Game」クラスから「Score」クラスへ向かって関連を引きましょう。 1組のゲームには、複数プレーヤーのスコアが記録できます。 つまり、ここにも、スコアシートとゲームの間と同じような関連が引けそうですね。

* 「Score」クラスと「Game」クラスの間に関連を引く。 * 「Score」クラス側の関連の多重度を「1..*」に設定する。 * 「Score」クラス側の関連端には関連端名として「scores」を設定する(複数のスコアが記録できることを反映した)。 * 「Game」クラス側の「集約」のプルダウンメニューから「aggregate」を選択する( ゲームとスコアの間に関連を引いた )。

{full-width}
Figure 37. ゲームとスコアの間に関連を引いた
スコアとフレームの間に関連を追加する

最後に、「Score」クラスから「Frame」クラスへ向かって関連を引きましょう。 フレームのオブジェクトをいつ用意するのかには、いくつか選択肢があります。 たとえば、ゲームを用意したときに全フレーム分用意すると決めることもできるでしょう。 あるいは、ゲームのい進行に合わせて、その都度フレームを追加すると決めることもできるでしょう。 いくつかの選択肢があるとき、それらからいずれを選択するのかを決定するのは、多くの場合設計時の決定事項です(このこと設計事項、設計項目、設計事由などと呼ぶ人たちもいます)。

このチュートリアルでは、スコアのオブジェクトを用意したときは、常に10フレーム分のフレームのオブジェクトも一緒に用意することとします。 この考えを選択したのは、表示や出力の際に、未投球のフレームについても、それらのフレームのオブジェクトを参照すれば、未投球の処理で特別な扱いが減られると考えたからです。 この場合、フレームとスコアは同時に作成されるので(ライフサイクルが同じなので)、集約の設定もコンポジションにしておきます。

  • 「Game」クラスと「Frame」クラスの間に関連を引く。

  • 「Frame」クラス側の関連端の多重度を「10」に設定する。

  • 「Frame」クラス側の関連端には関連端名として「frames」を設定する(複数のフレームが記録できることを意識した名前にした)。

    • 集約のプルダウンメニューの中から「composite」を選択する( スコアとフレームの間に関連を引いた )。

    • 「Score」クラス側の関連端の表示が、黒塗りのダイアモンド(コンポジションのシンボル)に変わる。

{full-width}
Figure 38. スコアとフレームの間に関連を引いた

これで、いったん、ボウリングのゲームスコアを表した構造のモデルができました。

まとめ

ボウリングのゲームスコアを記録するスコアシートの構造を検討しました。

構造のモデルを作成した手順

構造のモデルに登場する構成要素や要素間の関連を見つけ出すために、 スコアシートの構造のモデルを作成した手順 のような手順を使いました。

スコアシートの構造のモデルを作成した手順
  1. スコアシートを観察して、どのような要素で構成されているか洗い出した。

  2. スコアシートの実例をそのまま使ってオブジェクト図で表した。

  3. オブジェクト図の要素や要素間のつながりを観察して、クラス図を作成した。

まず、オブジェクト図をつくることで、オブジェクトを洗い出し、オブジェクト同士のつながり(リンク)を発見しました。 そして、オブジェクト図を参照しながら、クラス図を作成しました。 クラス間の関連の関連端名や多重度を検討する際は、オブジェクト図におけるリンクの数などを判断材料にしました。

この段階の構造のモデルはまだ未完成

ここで作成したクラス図には、検討の余地が残っています。 たとえば、いずれのクラスにも操作が定義できていません。 これは、プレーするのに従ってスコアをつけるときの動作(振る舞い)を検討していないからです。 また、動作を検討する中で、属性や関連についても追加や修正が必要になる場合があります。

そこで、続いて振る舞いのモデルを検討します。 振る舞いのモデルの作成が進むにつれて、構造のモデルも追加・修正されることになるでしょう。