UML

組込みエンジニアとしての活動
基礎UML
  1. はじめに
    1.  今日は、インプレスから出ています。基礎UML (UML2対応) 2600円 著 テクノロジック アート監修 長瀬嘉秀、橋本大輔
  2. UMLを理解しよう。
  3. オブジェクト指向を理解しよう。
  4. UMLを使用したオブジェクト指向によるアプリケーションの設計
    1. ユーザー要件と業務の把握
      1. アプリケーションの概要を把握しよう。
      2. 業務を把握しよう
        1. 誰にでもわかる業務フローの作成
        2. アクティビティ図とは
      3. ユーザー要件を把握しよう
        1. 1 ユーザー要件とは
      4. 必要なアプリケーションを考察しよう
        1. ユースケース図とは
      5. システム全体像を把握する。
    2. 仕様の決定1:シナリオとオブジェクト
      1. 仕様を決定しよう
        1. 仕様の重要性
      2. シナリオを作成して仕様を明確にしよう
      3. オブジェクトの関係を把握しよう
    3. 仕様決定2:オブジェクトの状態 
      1. オブジェクトの状態とその移り変わりを明確にしよう
    4. 仕様決定3:クラスとクラス間の関係
      1. クラスの概念を把握しよう
        1. クラスとオブジェクト
        2. クラス図とは
        3. クラス図を作成しよう。
    5. 仕様の決定4:アプリケーション化の検討 
      1. アプリケーションの動作の流れを検討しよう
        1. シーケンス図とは
          1. シーケンス図の要素一覧
          2. 相互作用 
          3. ライフライン
          4. 実行オカレンス 
          5. メッセージ
        2. シーケンス図を作成しよう
        3. 公演を検索する
        4. 残席状況を参照する
        5. チケットを予約する。
        6. 処理の全体像を確認する
      2. クラス図を詳細化しよう
        1. 詳細化のポイント
      3. 詳細なクラス図を作成しよう
    6. コーディング
      1. UMLのモデルに基づくコーディング
        1. チケット予約アプリケーションのコーディング
        2. 地域クラスとジャンルクラスのコーディング
        3. 会場クラスと公演クラスのコーディング
        4. チケット予約管理クラスのプラグラムを見ていきます。
        5. カレンダーの比較方法
        6. 実装クラス図
        7. 公演検索テストクラスのコーディング
  5. さいごに

はじめに

 今日は、インプレスから出ています。基礎UML (UML2対応) 2600円 著 テクノロジック アート監修 長瀬嘉秀、橋本大輔


 こちらは、以前から持っていた本でしたが、組み込みエンジニアには、アプリケーションの設計能力も必要であるので鍛えられます。主に業務把握で使用するアクティビティ図、アプリケーションに必要な機能を表現するユースケース図、システム全体像を把握するコンポーネント図、仕様の決定 シナリオとオブジェクト(クラス図、オブジェクト図、シーケンス図、ステートマシン図)などの理解を深められ、シナリオとオブジェクト図で大まかな構造をつかんで、クラス図を作り、シーケンス図を使ってより詳しいクラス図が作れます。最後にJAVAのコードにする。このようなことが実例を交えて学ぶことができます。要求定義から設計、コーディングまでの流れが理解できますので、何回も読んで自分にしみこませて、ものにすると1つのパターンが自分の中に出来上がりますので、いい経験になったと思う一冊です。最後のコーディングでクラス変数とクラスメソッドが肝になるのでお楽しみしてほしいところです。それでは、行きましょう。

UMLを理解しよう。

オブジェクト指向を理解しよう。

UMLを使用したオブジェクト指向によるアプリケーションの設計

ユーザー要件と業務の把握

アプリケーションの概要を把握しよう。

    構築するアプリケーションの概要把握

業務を把握しよう

   1 業務把握とは

   2 業務を把握するためには

誰にでもわかる業務フローの作成

     アクティビティー図を使用しましょう。

アクティビティ図とは

 それぞれの処理の状態を記述し、各状態間の遷移を示すことで、1連の処理を構成する状態の関係を表すダイアグラムです。

   5 アクティビティ図を作成しよう

ユーザー要件を把握しよう

1 ユーザー要件とは

アプリケーションに対するユーザー要求のことで、アプリケーションの開発を始める前に把握しておく必要がある。                              

   2 ユーザー要件の収集

必要なアプリケーションを考察しよう

 1 ユーザーとの調整

 2 アクティビティ図を用いた機能の考察  

ユースケース図とは

アプリケーションに必要な機能をユースケース図で表現できる。アクティビティ図と同様に、システムの知識のないユーザーも容易に理解することができる。

 4 ユースケース図を作成しよう  

 5 最初のスコープの決定

システム全体像を把握する。

3.5.1 コンポーネント図とは
 コンポーネント図は、コンポーネントと呼ばれるソフトウェア部品の構造を表現するためのダイアグラムです。
3.5.2 コンポーネント図を作成しよう

仕様の決定1:シナリオとオブジェクト

仕様を決定しよう

 Capter 3で把握した機能を詳細化する上で重要な役割を果たすのが仕様です。仕様とはユーザーの要件に基づいて、システムのあるべき姿を具体化したものです。仕様は、システムの機能構成、画面、操作法など、多岐にわたります。

仕様の重要性

 仕様を決定する際は、見る人によって違う解釈されないように、具体的に記述する必要があります。仕様を適切に記述できるかどうかが、その後のプロジェクトの成否を左右します。このため、仕様の決定は重要です。Capter4からChpter7では、Capter3で把握したユーザの要件や業務を元に、UMLの各種ダイヤグラムを用いて、システムを構成するクラス構造オブジェクトの相互作用状態遷移などを表現し、仕様を決定する。

シナリオを作成して仕様を明確にしよう

  仕様を決定する上で必要となるのがシナリオです。
 シナリオとは、ユースケースを具体的に実行した場合の流れを文章で記述したものです。シナリオは、システムのある時点におけるスナップショットです。

4.2.1 シナリオを作成するには

4.2.2 シナリオの記述

4.2.3 シナリオを作成しよう

オブジェクトの関係を把握しよう

 4.2.3で記述したシナリオ1から、オブジェクトとオブジェクトの関係と構造を、オブジェクト図を用いて明確にする。

 4.3.1 オブジェクト図とは
 アプリケーション設計では、シナリオで表現された、アプリケーション実行中のある瞬間における各オブジェクトの関わり合いを見る必要がある。特に、オブジェクトどうしが複雑に絡み合っている場合、その必要性が高まります。そのためには、オブジェクトの関係や構造を把握するためのダイヤグラムが必要になっています。
 オブジェクト図はシナリオに対応しています。つまり、オブジェクト図もシナリオ同様に、ある時点におけるスナップショット

4.3.2 オブジェクト図を作成しよう

仕様決定2:オブジェクトの状態 

 これまで、オブジェクト図を用いて、ユーズケースを構成するオブジェクトの静的な構造を見てきました。オブジェクト指向では、ある1つのオブジェクトに着目し、そのオブジェクトのアプリケーション中での普遍的な状態の変化を動的な流れで把握することが必要になります。UMLではステートマシン図というダイヤグラムを使用して、これを表現します。

オブジェクトの状態とその移り変わりを明確にしよう

 1 オブジェクトの状態

 2 ステートマシン図とは
       イベントで状態変化することをオブジェクトに絞って分析する。

 3 ステートマシン図を作成しよう

仕様決定3:クラスとクラス間の関係

クラスの概念を把握しよう

クラスとオブジェクト
クラス図とは


 集約 
  全体と一部で、 全体に白抜き四角 ◇
 コンポジット ◆
  全体と部分のライフサイクルがほぼ同じでより強い「全体ー部分」の関係を表します。
  すなわち、「全体」クラスが消滅する際に、、「部分」クラスも消滅します。
       

クラス図を作成しよう。

仕様の決定4:アプリケーション化の検討 


 チャプター6までで、チケット販売会社「ぺあ」の事例に登場するオブジェクトの構造、さらに状態との移り変わりをモデルで表現できました。ここでは、アプリケーションの構築に向けて、オブジェクトの詳細な振舞をシーケンス図で表現します。 
 オブジェクト指向の世界では、何らかの機能を実現するために、オブジェクト間がメッセージのやり取りを行って振る舞いを呼び出します。このようなメッセージのやり取りを相互作用と呼びます。UMLではこのようなメッセージのやり取りを表現するためのダイヤログとして相互作用図が用意されています。代表的な相互作用図には、シーケンス図とコミュニケーション図があります。シーケンス図は、相互作用を時系列に表現するダイアグラムです。このダイアグラムにより、ある機能を実現するためにオブジェクト間がどのような手順でメッセージをやり取りを行うのかを明確に示すことができる。

オブジェクト図は、オブジェクト間の関係に着目して相互作用を表現したい場合に使用します。

オカレンスとは、
 部品構造内の部品の、ある名前付き使用についての情報を格納するデータベースオブジェクト

アプリケーションの動作の流れを検討しよう

シーケンス図とは
シーケンス図の要素一覧

    要素     名称      内容

    sd    相互作用     ある機能を実現するためにオブジェクト間がメッ                     
                  セージをやり取りする単位を示す。

          ライフライン   相互作用に参加するオブジェクトやクラス、コン                   
                  ポーネント等を示す。

          メッセージ    ライフライン間で行われるやり取りを示す。同期、                  
                  非同期、同期の戻りの3種類が存在する。

          実行オカレンス  ライフラインが何らかの処理を実行している区間を
                  示す。

          生成メッセージ  ライフラインのインスタンスを生成するメッセージ
                  を示す。

相互作用 


 相互作用はある機能を実現するためにオブジェクト間がメッセージをやり取りする単位を表します。相互作用のフレームの中にシーケンス図を記述します。フレームのヘッダ部分にはシーケンス図の名前を記述し、名前の隣にはシーケンス図(Sequence Diagram)を表すsdという記号をつけます。

ライフライン

 ライフラインは相互作用に参加するオブジェクトやクラス、コンポーネント等を表します。ライフラインの垂直の破線はオブジェクトが生存している期間を表します。ここでいう生存とは、ライフラインの破線で示される期間、オブジェクトが存在することです。
 

実行オカレンス 

 その区間でライフラインが活動していることを表します。実行オカレンスは省略が可能です。

メッセージ


同期メッセージ 
 同期メッセージは、先端が塗りつぶされた三角の実線で表します。このメッセージによって       起動された操作が終了しないと、次の操作へ進めないことを意味します。メッセージ名は以下のように記述します。

 メッセージ名(引数1=値、引数2=値)

非同期メッセージ
 非同期メッセージは、先端が「く」の字の矢印の実践であらわします。このメッセージによって起動された操作が終了しなくても、次の操作へ進めることを意味します。メッセージ名の記述法は同期メッセージと同じです。

同期の戻り
 同期の戻りメッセージは、先端が「く」の字の矢印の点線で表します。同期メッセージによって起動された操作が終了するタイミングや同期メッセージの戻り値を明記したい場合に記述します。メッセージ名は、以下のように記述します。

     戻り値の型同期メッセージの名前(_):戻り値


下記を見ると上記のようになっています。

相互作用
シーケンス図
残席シーケンス図
チケット予約シーケンス図

 ライフライン

シーケンス図を作成しよう

 Capter6までで検討したオブジェクトは、「ぺあ」のアプリケーションが扱うデータに着目して抽出したものです。しかし、アプリケーションソフトを構築するには、ユーザーインターフェースである画面や、計算や判断を行うビジネスロジックなど、さまざまな機能を設計する必要があります。設計段階では、このような機能についてもオブジェクトとして抽出し、それぞれに「ユーザインターフェース」「ビジネスロジック」「データアクセス」などの分類を持たせていきます。オブジェクトをこのような役割ごとに分類することで、各オブジェクトの責任範囲が明確になり、ユーザーの要件によって仕様を変更しなければいけない場合でも、どのオブジェクトを修正したら良いかが容易に把握できるようになる。
 上述のようなオブジェクトの分類を表現する際には、オブジェクト名の上にステレオタイプを記述することで、そのオブジェクトの分類が明確になります。

オブジェクトの分類

 チケット販売会社「ぺあ」の事例では、Aさんは、「ぺあ」のサイトにアクセスして、チケットの予約を行います。今まで作成してきた各図では、Aさんとシステムの間にある「ユーザインターフェース」は意識していませんでした。このモデルでは、これをオブジェクトとして扱うこととします。オブジェクト名は、「チケット予約画面」とします。
 また、画面から入力された情報を基にさまざまな計算や判断を行う部分(ビジネスロジック)も必要になります。この部分もオブジェクトとして扱うこととします。オブジェクト名を「チケット予約管理」とします。 
 上記の点を踏まえて、Capter6までで導出したオブジェクトに加えて、チケット予約画面オブジェクトとチケット予約管理オブジェクトをライフラインとしてシーケンス図に登場させます。また、各オブジェクトの分類として、先ほど追加したチケット予約画面には、表示部を表すPresentation チケット予約管理には,Domain その他
 Capter6までで導出したオブジェクトは、データベースなどに永続データとして記録されるオブジェクトのため、DataSourceというステレオタイプを付加します。
 シナリオ1チケット予約(地域検索)の流れを確認しながら、シーケンス図でそれをどう表現するのか確認して行きます。なお、このシナリオを1枚のシーケンス図で表現すると、ダイアグラムが大きくなりすぎてしまい、可読性が悪くなるため、「公演を検索する」「残席状況を参照する」「チケットを予約する」の3つのシーケンス図に分割して表現します。

シナリオ1「チケット予約(地域検索)」

シナリオ名 チケット予約(地域検索)

シナリオ概要 地域検索を行い、希望の観劇チケットを予約する

事前条件   ・Aさんはチケット販売会社「ぺあ」に次の内容(住所=東京都文京区××、       
        電話番号=03-1111-2222)で顧客登録をし、顧客ID「xyz123」を発行されて
        いる。
       ・Aさんは、チケット販売会社「ぺあ」のサイトに顧客ID=xyz123でログイン
        している

ステップ   ①Aさんがジャンルから「観劇」を選択し、地域を「関東」に絞って地域検       
        索を行う。
       ②該当公演から、「2003年3月7日18時」に「トウキョウ劇場」で「劇団夏季」が
        講演する「マウス」のチケットの残席状況を参照する。
       ③残席があったので、「マウス」のS席(11000円)のチケットを予約する。

事後条件  「2003年3月7日 18時」に「トウキョウ劇場」で「劇団夏季」が講演する「マ     
       ウス」のS席のチケットがAさんによって予約されている。

公演を検索する

 Aさんは、「ぺあ」のチケット購入サイトで、観劇というジャンルを選択します。すると画面が観劇専用の検索画面に移ります。チケット購入者であるAさんは「ぺあ」のサイトにアクセスし、顧客IDを入力してログインしています。

ジャンル選択


 次に、Aさんは、画面に対して地域「関東」を入力して検索を行います。他にも画面からは公演名、日時、会場名が検索条件として入力できることが確認できます。検索条件を入力して検索を行うと、検索結果として公演の一覧が画面に表示されます。

チケット検索画面


 この流れをシーケンス図上で表すと、まず、アクタ「チケット購入者」からライフラインチケット予約画面に対してメッセージ「ジャンルを選択する」を送信されます。するとチケット予約画面は、検索画面に表示するため、自分自身に対してメッセージ「検索画面を表示する」を送信します。
 次にアクタ「チケット購入者」がライフライン「チケット予約画面」メッセージ「検索を行う」を送信します。この時、画面に対して入力される検索条件がメッセージの引数として渡されます。すると、このメッセージを受信したライフライン「チケット予約画面は、検索処理などのビジネスロジックを担当するライフライン「チケット予約管理」に対して上記と同様のメッセージを最初の画面でユーザ選択した「ジャンル名」を引数に加えて送信します。ライフライン「チケット予約管理」は検索処理に必要なデータを取得するため、ライフライン「公演」、「ジャンル」、「会場」、「地域」に対してメッセージを送信します。取得したデータを基に検索条件に適合する公演を抜き出し、戻り値「検索結果」としてライフライン「チケット予約画面」に返します。最後にライフライン「チケット予約画面」は検索結果を画面に表示します。

公演を検索シーケンス
観劇チケット検索

図7.14観劇専用検索画面

残席状況を参照する

  Aさんは画面上に表示された検索結果から、残席状況を参照する公演を選択します。すると画面には選択した公演の詳細情報が表示され、残席状況が参照できます。

検索結果から、残席状況を参照結果

 この流れをシーケンス図で表すと、まずアクタ「チケット購入者」からライフライン「チケット予約画面」に対してメッセージ「残席状況を参照する」が送信されます。このとき、選択した公演の「公演名」と「日時」が引数として渡されます。すると、このメッセージを受信したライフライン「チケット予約画面」はライフライン「チケット管理画面」に対して、上記と同様のメッセージを送信し、残席状況に関するデータ収集を依頼します。ライフラインチケット予約管理は、残席状況に関数するデータを取得するため、引数として受け取った「公演名」「日時」に適合するライフライン「公演」にデータを取得のメッセージを送信します。ライフライン「公演」はライフライン「チケット」にメッセージを送信し、自分に対して発行されたチケットのうち、まだ、予約されていないチケットを取得して、戻り値「残数状況」として返します。この「残数状況」は、ライフライン「チケット予約管理」からライフライン「チケット予約画面」に渡され、最後に画面に表示されます。

残席状況
チケットを予約する。

 Aさんは画面上に表示された公演の残席状況を確認し、予約を行います。すると、予約結果が画面に表示されます。

チケット予約

 この流れをシーケンス図上で表すと、まずアクタ「チケット購入者」からライフライン「チケット予約画面」に対してメッセージ「チケット予約する」が送信されます。この時、公演名、日時、座席が引数として渡されます。すると、このメッセージを受信したライフライン「チケット予約画面」はライフライン「チケット予約管理」に対して上記と同様のメッセージを引数「顧客ID」を加えて送信し、チケットの予約を依頼します。ライフライン「チケット予約管理」は、引数として受け取った「公演名」と「日時」に適合するライフライン「公演」にメッセージ「予約する」を送信します。ライフライン「公演」はライフライン「チケット」にメッセージを送信し、予約を依頼する。ライフライン「チケット」は予約を行うにあたって、引数として渡された「顧客ID」をもとにライフライン「顧客」にメッセージを送信し、顧客情報の取得を行います。チケットの予約が終了したら、戻り値として「顧客情報」が「チケット予約画面」まで返され、最後に予約結果の画面が表示されます。

処理の全体像を確認する

 シナリオ1「チケット予約(地域検索)」をもとに作成したシーケンス図は、「公演を検索する」、「残席状況を参照する」、「チケットを予約する」の3つに分割されてています。このように大きな処理をいくつかに分割することは、ダイアグラムの可読性を上げる一方、処理の全体像がとらえにくくなるというデメリットがあります。このため、UMLでは処理の全体像を確認するためのダイアグラムとして相互作用概念図が容易されています。以下は相互作用概念図の例です。 

相互作用概念図

 相互作用概要図は、アクティビティ図に非常によく似た表記を使用します。アクティティビティ図と表記上違う点は、アクティビティ図の手順の1つ1つが「アクティビティ」であるのに対して、相互作用概要図の手順が「相互作用」や「相互作用オカレンス」である点です。つまり、相互作用概要図では、シーケンス図などの相互作用図の実行順序を表現しています。
 チケット販売会社「ぺあ」の例では、作成した3つのシーケンス図のうち、「公演を検索する」をまず実行するため、開始ノードから相互作用オカレンス「公演を検索する」までのコントロールフローを引きます。その後、再検索を行う場合と残席状況を参照する2つの流れに処理を分かれるため、これを分岐として表現します。再検索を行う流れは、分岐のひし形から相互作用オカレンス「公演を検索する」までのコントロールフローとして、残席状況を参照する流れは、分岐のひし形から相互作用オカレンス「残席状況を参照する」までのコントロールフローとして表現します。同様に、その後、再検索を行う場合とチケットを予約する2つの流れに処理が分かれるため、これも、分岐として表現します。再検索を行う流れは、分岐のひし形から相互作用オカレンス「公演を検索する」までのコントロールフローとして、チケットを予約する流れは、分岐のひし形から相互作用オカレンス「チケットを予約する」までのコントロールフローとして表現します。最後に、相互作用オカレンス「チケットを予約する」から処理の終了を表す終了ノードへのコントロールを引きます。

条件のひし形は、アクティビティ図から取ってきている。

相互作用概念図

クラス図を詳細化しよう

詳細化のポイント

 UMLのメリットで説明したとおり、UMLの各図は、システム開発の各段階に応じて、自由に粒度を変更できる。

 ■クラスの追加
  チケット予約画面、チケット予約管理の2つのオブジェクトの追加

 ■関連、振舞い、多重度、分類の修正
  クラスが追加されたので、関連、振舞いも見直します。クラスが追加された結果、別のクラスに新たな関連、振舞いが追加されるかもしれないからです。シーケンス図のメッセージにしたがって、全クラスの関連、振舞いを正確に反映して行きます。さらに、前節のシーケンス図にならい、ステレオタイプを使用して各クラスの分類を明確にします。上記の内容を反映したクラス図は、図7.23のような形式になります。

詳細クラス図

 図7.23で、属性と操作の前にプラス(+)とマイナス(ー)の記号があるのがわかるでしょう。これらの記号は可視性と呼ばれます。可視性は、クラスが持つ属性や操作を他のクラスにどこまで公開し、アクセスさせるかを定義します。オブジェクト指向のメリットを活かす為にも、属性は他のクラスにアクセスさせず、「~取得」のような属性アクセス用の操作を用意するのが一般的です。以下の4レベルがあります。

 ■パブリック(+) 他のすべてのクラスからアクセス可能
 ■プロテクテッド(#) このクラスの属性や操作を継承するサブクラスからのみアクセ             ス可能
 ■プライベート(ー) このクラス自身からのみアクセス可能
 ■パッケージ(~) このクラスと同じパッケージに所属する他のクラスからアクセス可           能

 Capter6で作成した概念クラス図では、操作が記述されていませんでした。ここでは、シーケンス図のメッセージを基に、操作を記入してみましょう。

シーケンス図からクラスに操作追加

上記に倣って、
 シーケンス図の作成段階で追加された「チケット予約画面」と「チケット予約管理」という2つのオブジェクトをクラスとして定義します。シーケンス図から、各オブジェクトに以下の振舞いがあることが分かります。
■「チケット予約画面」
 ジャンルを選択する(ジャンル名)
 検索を行う(地域名、公演名、日時、会場名)
 検索結果を表示する(検索結果)
 残席状況を参照する(公演名、日時)
 残席状況を表示する(残席状況)
 予約する。(公演名、日時、座席)
 予約結果を表示する(公演名、日時、座席、顧客情報)
■「チケット予約管理」
 検索を行う(ジャンル名、地域名、公演名、日時、会場名):検索結果
 座席状況を取得する(公演名、日時):残席状況
 予約する(公演名、日時、座席、顧客ID)

詳細なクラス図を作成しよう

詳細なクラス図

コーディング

UMLのモデルに基づくコーディング

 Chapter7までで作成したUMLモデルからアプリケーションを開発する際、モデルの内容をどのようにプログラミング言語で表現すればよいでしょうか。ここでは、プログラミグ言語としてJavaを用い、UMLで作成したモデルからどのようにコーディングできるのかを説明する。

  8.1.1 UMLとJAVA

チケット予約アプリケーションのコーディング
検索シーケンス図

 ここでは、検索条件の入力と検索結果の表示を行う「チケット予約画面」オブジェクトは省略し、テストコードに吸収します。
 詳細クラス図の関連を見ながら、これらクラスのインスタンスであるオブジェクトの生成順を見ていくと、まず、「ジャンル」や「地域」が生成されます。次に、どこかの地域に所属する会場が生成されます。そして最後に、あるジャンルに所属し、どこかの会場で開催される「公演」が生成されます。つまり、これらのクラスの中で、ジャンルや地域は他のクラスに依存することがない最も独立性の高いクラスであり、逆に公演は最も他のクラスへの依存度が高いクラスといえます。他のクラスへの依存度が高ければ、高いほど通常プログラムは複雑になります。

地域クラスとジャンルクラスのコーディング

import java.util.*;

public class Area{

  //属性の定義

  private String areaName;

     private static ArrayList areaList = new ArrayList();

    public String getAreaName(){

return areaName;

   }

   Area(String areaName){

   this.areaName =  areaName;

   }

   public static void setAreaList(Area area){

areaList.add(area);

   }

}

import java.util.*:

public class Genre{

private String genreName;

private static ArrayList genreList =  new ArrayList();

   public String getGenreName(){

return genreName;

}

Genre(String genreName){

this.genreName = genreName;

}

public static void setGenreList(Genre genre){

genreList.add(genre);

}

}

会場クラスと公演クラスのコーディング

 次に会場クラスのプログラムを見てみましょう。

import java.util.*;

public class Venue{

private String vanueName;

private Area area;

private static ArrayList venueList = new ArrayList();

public String getVenueName(){

return venueName;

}

Venue(String venueName, Area area){

this.vanueName = venueName;

this.area = area;

}

public static void setVenueList(Venue venue){

venueList.add(venue);

}

④public Area getArea(){

return area;

}

}

 会場オブジェクトは、既に存在しているどこかの地域オブジェクトに所属する必要があるため、地域クラスとの関連をコーディングしなければなりません。通常、クラス間の関連をプログラムとしてコーディングする場合、このように関連先のクラスを型とする属性を定義します。(多重度が「1:多」の関連の場合はコンテナを用いて関連をコーディングすることもあります。)
 また、《Domain》などの他のクラスから、この会場クラスを経由して関連先の地域クラスにアクセスする操作を④に定義します。
 このようなオブジェクト指向における関連のコーディングは「キー」でエンティティ間の関係を表現するリレーションデータベースとの大きな違いでもあります。
 一方、公演オブジェクトも所属先のジャンルオブジェクト、開催先の会場オブジェクトとの関連を会場クラスと同様に属性としてコーディングする必要があります。
import java util.*;

public class Performance{

private String performanceName;//公演名

private Calender performanceDate;//日時

private String thaterCompanyName;//劇団名

private Genre genre;//ジャンル 関連

private Venue venue;//会場 関連

private static ArrayList performanceList  = new ArrayList();

public static ArrayList getPerformanceList(){

return performanceLista;

}

Performance(String performanceName, Calendar, performanceDate,String               teaterCompanyName, Genre genre, Venue venue){

this.performanceName = performanceName;

this.performanceDate = performanceDate;

this.theaterCompanyName = teaterCompanyName;

this.genre = genre;

  this.venue = venue;

public static void setPerformanceList(Performance performance){

performanceList.add(performance);

}

public String getPerformanceName(){

return performacneName;

}

public Calender getPerformanceDate(){

return performanceDate;

}

概念クラスの完成図

  public Genre getGenre(){

return genre;

}

public Venue getVenue(){

return venue;

}

public string getVenueName(){

return venue.getVenueName();

}

}

チケット予約管理クラスのプラグラムを見ていきます。

 Capter7で Domainクラスはビジネスロジックを担当し、通常のDataSourceのクラスにアクセスしながら、計算を行ったり、判断を行ったり、します。コーディング対象の公演検索部分のうち、実際に検索の処理を担当するのはこのクラスです。

8.1.5 チケット予約管理クラスのコーディング

import java.util.*;

public class TicketReserveCortrol{

private Performance performance;

private Genre genre;

private Venue venue;

private Area area;

public ArrayList performanceSerch(String performanceName, Calender

performanceDate, String genreName,

        String areaName){

//「検索を行う(公演名、日時、ジャンル名、地域名)

       会場名は?performance にあったような?

boolean searchFlag;

ArrayList serchResult = new ArrayList();

ArrayList performanceList = Performance.getPerformanceList();

Iterator performanceIterator = performanceList.iterator();

while(performanceIterator.hasNext()){

performance =(Performance)performanceIterator.next();

serchFlag = true;

//公演名の比較

if(performanceName != null &&

performance.getPerformanceName()!=performanceName){

serchFlag = false;

}

//日時の比較

if(performanceDate!=null &&

performance.getPerformanceDate().

after(performanceDate)== true ||

  performance.getPerformanceDate().

before(performanceDate)==true){

searchFlag = false;

}

genre = performance.getGenre();

//ジャンル名の比較

if(genreName != null && genreName != genre != genre.getGenreName()){

serchFlag = false;

}                       

venue = performance.getVenue();

area = venue.getArea();

//地域名の比較

if(areaName != null && areaName != area.getAreaName()){

serchFlag = false;

}

if(serchFlag == true){

serchResult.add(performance);

}

}

return serchResult;

}

}

  Chapter 7のシーケンス図「公演を検索する」において、ライフライン「チケット予約管理へのメッセージ「検索を行う」はユーザが入力した検索条件から該当する公演を検索し、検索結果を返します。
 上記のプログラムのperformanceSearch()メソッドがこれに当たります。このメソッドでは、まず①で公演クラスにアクセスし、公演クラスのインスタンス管理用属性「PerformanceList]を取得します。次に、PerformaceListから公演クラスのインスタンスを1つずつ取り出し,②のwhile文で繰り返しながら引数の検索条件と一致するか判断しています。もし一致する場合、③で戻り値「searchResult」に公演を登録します。

公演検索シーケンス図
詳細クラス図

Java では、Calendar クラスは、after()、before()、および equals() メソッドを使用して日付を比較するメソッドを提供します 。その仕組みは次のとおりです。

カレンダーの比較方法
  • after(Object when): Calendar オブジェクトが指定された日付より後にある場合は true を返します。
  • before(Object when): カレンダーオブジェクトが指定された日付より前である場合に true を返します。
観劇チケット検索
詳細クラス図
実装クラス図

前述したプログラムを基に、コーディングレベルのクラス図を作成すると、図8.3のようになります。(コンストラクタは省略しています。)

    実装クラス図とCapter7で作成した詳細クラス図との大きな違いは、以下です。

    ■クラス名、属性名、操作名が英訳されている点

    ■<<DataSource>>の各クラスにインスタンス管理用の属性、操作が定義されてい

     る点

    ■関連の誘導可能性(Capter6参照)が明確になっている点(関連の方向)

 ■クラス間の関連が属性としてコーディングされている点

  (関連の矢印の先にあるクラスを型とした属性が定義されている)

   なお、属性や操作に下線が付けられているものは、それがクラススコープ(クラス変数、クラメソッド)であることを示している。  英語 クラス図

詳細クラス図
公演検索テストクラスのコーディング

 最後に、ここで登場したプログラムを動作させてみましょう。ここでは、ユーザが入力した「ジャンル名」と「地域名」から該当する公演を検索し、検索結果を返すチケット予約管理クラスの操作「検索を行う()」テストプログラムを作成します。

 公演を検索するテストプログラムを作成するためには、検索対象となる「公演オブジェクト」やその関連先である「ジャンルオブジェクト」、「会場オブジェクト」、さらに会場オブジェクトの関連先である「地域オブジェクト」をあらかじめ生成しておく必要がある。

ここで、各クラスのテスト用インスタンスとして、図8.4に示すオブジェクトをあらかじめ作成します。

公演検索テストプログラム

import java.util.*;

import java.text.*;

public class TestPerformanceSearch{

    public static void main(String[] args){

TestPerformanceSearch testPerformanceSearch = new TestPerformanceSearch();

①testPerformanceSearch.setTestData();

TicketReserveControl ticketReserveControl = new TicketReserveControl();

Calender performanceDate = Calender.getInstance();

            ②ArrayList searchResult = ticketReserveControl.performanceSearch(null, null,”観劇”,”    

            関東”);

//ArrayList searchResult = ticketReserveControl.performanceSearch(null,null,”観劇”,”

関西”);

            Iterator searchResultIterator = serchResult.iteratior();

③System.out.println(“ヒット件数=”+searchResult.size());

String format = “yyyy/MM/dd HH:mm”;

while(searchResultIterator.hasNext()){

Performance resultPerformance = (Performance)searchResultIterator.next();

System.out.println(“公演名=” + resultPerformance.getPerformanceName() +

“会場名=” + resultPerformance.getVenueName() + “ 日時=” + new 

SimpleDateFormat(format).format(resultPerformance.getPerforamanceData().getTime()));

}

private void setTestData(){

Area kanto = new Area(“関東”);

Area.setAreaList(kanto);

Area kansai = new Area(“関西”);

Area.setAreaList(kansai);

Venue tokyoVenue = new Vanue(”トウキョウ劇場”,kanto);

Venue.setVenueList(tokyoVenue);

Venue artsSophia = new Vanue(“アーツソフィア”,kanto);

Venue.setVenueList(artsSophia);

Venue omgCultureHall = new Venue(“OMG文化ホール”,kanto);

Venue.setVenueList(omgCultureHall);

Venue oosakaVenue = new Venue(“オオサカ劇場”,kansai);

Venue.setVenueList(oosakaVenue);

Venue kyotoHall = new Venue(“キョウト会館”,kansai);

Venue.setVenueList(kyotoHall);

Genre music = new Genre(“音楽”);

Genre.setGenreList(music);

Genre theatergoing = new Genre(“観劇”);

Genre.setGenreList(theatergoing);

Genre sports = new Genre(“スポーツ”);

Genre.setGenreList(sports);

Genre event = new Genre(“イベント”);

Genre.setGenreList(event);

Calendar performanceDate;

performanceDate = Calendar.getInstance();

performanceDate.set(2003,2,7,18,0);

performance.setPerformanceList(

    new Performance(”マウス”,performanceDate,”劇団夏季”,         

                                               theatergoing,tokyoVenue));

performanceDate = Caledar.getInstance();

       performanceDate.set(2003,2,7,18,0);

performance.setPerformanceList(

    new Performance(”ミス サイゴウ”,performanceDate,”劇団夏季”,         

                                               theatergoing,oosakaVenue));

performanceDate = Caledar.getInstance();

       performanceDate.set(2003,0,22,18,0);//0月は間違いではないかと思う。

performance.setPerformanceList(

    new Performance(”ミス サイゴウ”,performanceDate,”劇団冬季”,         

                                               theatergoing,artsSophia));

performanceDate = Caledar.getInstance();

       performanceDate.set(2003,1,8,19,0);// 年月日時分(秒)までをまとめて設定

performance.setPerformanceList(

    new Performance(”キッズ”,performanceDate,”劇団冬季”,         

                                               theatergoing,artsSophia));

performanceDate = Caledar.getInstance();

       performanceDate.set(2003,3,25,18,0);

performance.setPerformanceList(

    new Performance(”キッズ”,performanceDate,”劇団秋季”,         

                                               theatergoing,kyotoHall));

performanceDate = Caledar.getInstance();

       performanceDate.set(2003,3,1,18,0);

performance.setPerformanceList(

    new Performance(”スペラ座の達人”,performanceDate,”劇団春季”,         

                                               theatergoing,omgCultureHall));

}  

}

 上記のプログラムでは、まず①の「setTestData()」メソッドが呼ばれ、前述した各クラスのテスト用インスタンスが生成されます。この時、各クラスのインスタンス管理用属性にそのインスタンスを登録している点に注目してください。次に,②の1行目でチケット予約管理クラスの操作「検索を行う()」に対し、検索条件である「ジャンル名」と「地域名」が引数としてセットされ、公演の検索を行います。最後に③で検索結果一覧とヒット件数の表示を行います。

検索結果

〇分析、設計で作成したUMLモデルを基に、コーディングを行うことができました。

〇UMLとJAVAは、両方ともオブジェクト指向です。

〇実装クラス図とは、プログラムを基にしたコーディングレベルのクラス図であり、詳細クラウス図では定義していない属性や操作が追加されます。

概念クラス図
テストインスタンス
公演検索シーケンス

 

さいごに

 何回も読んで、開発した気になります。もっと真剣に読み込めば1つの案件を実施したことになります。実績になります。是非、読み込んで欲しい一冊です。私もこれで、4回目ですが、まだ読めば、気づくことがありそうです。あと、自分が購入したときは、2600円+税でしたが、949円で購入できるなんて、驚いています。これから、組み込みエンジニアを目指す人にも読んで欲しい一冊です。

コメント

タイトルとURLをコピーしました