オブジェクト指向設計 基礎講座

オブジェクト指向設計基礎講座
オブジェクト指向設計
基礎講座
日本エコシステム株式会社
1
オブジェクト指向設計基礎講座
1. 目的
近年のソフトウェア開発において、オブジェクト指向設計は必須となってきました。特にオブジェク
ト指向言語である Java を用いたプロジェクトのほとんどは、オブジェクト指向設計で実装されてい
ます。オブジェクト指向言語を使うからといって必ずしもオブジェクト指向設計を行う必要はありま
せんが、設計手法を知っているのと知らないのでは開発工程や実装内容に関する理解度が全く違いま
す。
オブジェクト指向設計の特性を理解し、実際の仕事に役立つスキルを習得することを目的として、本
資料では実際のプロジェクト運営手順のサンプルをまじえて、オブジェクト指向設計を解説していき
ます。
2. ユースケース駆動
オブジェクト指向に基づくプロジェクト運営で欠かせないのが、ユースケース駆動の概念です。
ユースケースとは、システムが備えていなければならない機能を列挙するもので、システムの境界線
を明確にする意図でも作られます。システムが必要としている全機能をユースケースに記述するため、
テストもユースケースを元に行われます。
顧客の立会い試験・総合試験でユースケースを元にしたテストを実施し、全てのユースケースが実
現できていることが確認できて納品となります。このようにユースケースを基準とした開発駆動方式
をユースケース駆動といいます。
ユースケース駆動でプロジェクトを運営することを明確にするために、
【参考資料】
『プロジェクトの
進め方』のような方針を策定するのも有効です。ユースケース駆動の場合、ユースケースは総合テスト
ケースと密接に結びつきますから、どのように総合テストを実施するかを具体的に決めておくことが
重要です。
3. ユースケース分析と総合テスト
設計者・開発者はまず、分析によってユースケースを抽出しなければなりません。言い換えれば、シ
ステムが必要としている機能を 1 つ 1 つ全て抽出しなければならない、ということになります。抽出し
たユースケースは、ユースケース図に記述するとともに、各ユースケースの詳細な内容をユースケース
記述に書いていきます。
ユースケースの抽出方針を明確にするために、
【参考資料】
『ユースケース分析の進め方』のような作
成手順を策定するのも有効です。特にユースケース駆動で開発を進める場合は、ユースケースの確認を
取るための総合テストケースとどう関連しているかについては、記述しておくべきです。
2
オブジェクト指向設計基礎講座
4. ユースケース図とユースケース記述
プロジェクトにおいてユースケースをどのように使うかについての方針が確定したら、実際にユー
スケース分析を行います。ユースケース分析は通常、要件定義書等の事前ドキュメントから起こすか、
もしくはユーザに直接ヒアリングして書き始めます。
ユースケースを記述する際の注意点は、次の通りです。
(1) システムが実現すべき機能ごとに 1 つのユースケースを記述する。
(2) 必ずアクターとの関連を記述する。ユースケースは、必ずいずれかのアクターに接続する。
(3) 2 つ以上の機能に共通の要素がある場合、汎化を行って共通ユースケースを抽出する。
ユースケースは、
「アクターから見たシステムの機能」であり、
「システムが外部(ユーザや連携いし
ている他システム)に提供する機能」です。そのため、ユースケースは必ずいずれかのアクターと接続
するように記述します。ただし、汎化や包含、拡張を行っている場合に限り、いずれのアクターとも接続
しないユースケースを記述することが可能です。
ユースケース図のサンプルは、次の通りです。
ユーザ登録する
一般ユーザ
ログインする
登録ユーザ
例えば何かしらのサービスを提供するポータルサイトを作成する設計の場合、ユーザ登録と登録ユ
ーザのログイン機能はほとんど必ずといっていいほど機能として用意されています。そうした機能ご
とに 1 つずつユースケースを記述します。(アクターから見た機能として、1 つ 1 つのユースケースを
抽出します)
3
オブジェクト指向設計基礎講座
ユースケース記述のサンプルは、次の通りです。
項番
ユースケースの名前
ユースケースの目的
事前条件
事後条件(正常)
事後条件(異常 1)
事後条件(異常 2)
基本アクター
関連するアクター
開始トリガー
ステップ
3
ユーザ登録を行う
一般ユーザがシステムにユーザ登録する。
システムの起動。トップページからの登録アクセス。
一般ユーザが登録されること。
必須項目に入力がない場合にエラーとなること。
必須項目は、次の通り。
1.
メールアドレス(ユーザ ID となる)
2.
パスワード
3.
ニックネーム
既存のメールアドレスを指定してユーザ登録を行おうとした場合にエラーとなること。
一般ユーザ
-
一般ユーザがユーザ登録を選択する。
1.
一般ユーザは、ユーザ登録を選択する。
2.
一般ユーザは、登録情報を入力する。
3.
システムは、ユーザ登録を行う。
3.1. 異常 1
必須項目が入力されていない場合にエラーとなること。
4.
備考
システムは、ユーザ登録完了、マイページ画面を表示する。
※ 本ユースケースより、分析の初期クラスとしてユーザを抽出する。
※ 入力必須項目の入力チェックの部分は、ビジネスルールとして抽出する。
※ 異常系は 1 項目しかないように見えるが、実際には必須入力のどれか 1 つが欠けるパ
ターンを全てテストする必要あり。(品質向上のため)最初は 1 つのテストでも構わない
が、後には全ての必須項目についての異常系総合テスト項目を追加すること。
※ 本ユースケースより、「ユーザ登録画面」を抽出する。
※ 本ユースケースより、「マイページ画面」を抽出する。
※ 本ユースケースより、モデルクラス「登録ユーザ」を抽出する。
備考欄は特に記述する必要ありません。このサンプルでは書かれていますが、個々の設計経緯をユー
スケースに書くか、それとも別途資料化するかは自由です。
4
オブジェクト指向設計基礎講座
5. 初期クラス図の作成とデータベース設計
ユースケースを記述し、システムが具備すべき機能が列挙できたら、個々のユースケース記述から初
期クラス図を作成します。
初期クラス図は分析クラス図ともいわれ、本質モデルを図にしたものとなります。本質モデルとは、
システムのプラットフォームが変わっても不変である業務ロジックの部分のことを指します。
誤解を恐れずに端的にいうならば、データベース構造を図にしたものです。クラス図は静的構造図で
すから、セッションをまたいでも破棄されない永続化データを持つ構造がクラス図になるといえるか
らです。Java による Web アプリケーション開発などで、永続化データといえばデータベースのデータ
のことを示すのが一般的です。
ログイン履歴
-ログイン履歴 ID
登録ユーザ
-ユーザ ID(PK)
-ユーザ ID(FK)
-パスワード
-日付
-ニックネーム
-ログイン成否
登録ユーザ履歴
-登録ユーザ履歴 ID(PK)
-ユーザ ID(FK)
-パスワード
-ニックネーム
-更新日時
-更新理由
例えば先ほどのポータルサイトのサンプルで、ユーザ登録の機能と、登録したユーザについての履歴
記録機能、ログインした登録ユーザのログイン履歴記録機能が規定されたとします。
その場合、上図のような静的構造が抽出できます。(ユーザ登録したデータを『登録ユーザ』テーブル、
登録ユーザのデータ更新履歴を『登録ユーザ履歴』テーブル、登録ユーザのログイン履歴を『ログイン履
歴』テーブルに、それぞれ格納する)
この図のような静的構造図は、コーディング上もそのままクラスとなることが多くなってきていま
す。オブジェクト指向分析とデータ中心指向分析は異なるため、本来、テーブル構造がそのままクラス
になるとは限らないのですが、近年では hibernate 等による O/R マッピングが発達してきたことから、
静的構造がデータベース構造に大変近くなってきています。
「データベース構造と同じようにクラスを作成し、O/R マッピングで DAO を構成して開発を進め
る」といった手法が採用されることが多く、更にこれを正式な手法として取り入れた「ドメイン駆動設
計(DDD)」も出てきました。
5
オブジェクト指向設計基礎講座
ユースケース記述に書かれている機能から導き出されるデータベース構造を初期クラス図とする手
法が有効です。複雑な機能を持つ場合、テーブルの分け方も複雑となり、一意に答えが定まらない場合
があります。そうしたケースでは、ユースケースもしくはその上位ドキュメントの要求仕様を考慮の上、
最適なデータベース構造を検討することになります。
いずれの場合でも、初期クラス図はデータベース構造とほぼ同じになります。
6. ドメイン駆動の適用と実装
ドメイン駆動設計(DDD)という開発手法があります。ドメインとはデータベースの行に相当する
データを操作するクラスであり、データベースの複数行に対する操作はリポジトリと呼ばれるクラス
で行います。このドメイン及びリポジトリに全ての業務ロジックを記述します。(ドメインとリポジト
リが本質モデルの部分となり、システムを流用・移植するときの対象となります)
サービス
リポジトリ
ドメイン
DAO
エンティティ
またドメインやリポジトリは通常コントローラから直接呼び出されず、サービスがインターフェー
スを持つことになります。(例えばユーザ登録の機能はユーザ登録サービスに対応する、など)
ドメインはデータベースの行データに対応するクラスですので、エンティティを持ちます。また 、
DAO はリポジトリもしくはドメインからアクセスされます。
ドメイン駆動設計は、設計や実装の手順を統一しやすい利点があります。以降の項で、実際に 1 行の
データを操作するパターン(ドメインを使うパターン)と、複数行のデータを操作するパターン(リ
ポジトリを使うパターン)をそれぞれ見ていきます。
6
オブジェクト指向設計基礎講座
6.1. 単一のデータを操作するパターン
ここでは説明簡略化のため、ポータルサイトでユーザ登録操作が実行された場合、データベースの登
録ユーザテーブルにレコードが 1 件追加される仕様であると仮定します。
ユースケースで機能がこのように規定された場合、設計手順は次のようになります。
(1) データベーステーブルとして『登録ユーザ』テーブルを抽出します。
(2) 登録ユーザテーブルに対応するエンティティクラスとして『登録ユーザ』クラスを抽出します。
(3) 登録ユーザテーブルに対応する DAO クラスとして『登録ユーザ DAO』クラスを抽出します。
(4) 登録ユーザテーブルに対応するドメインクラスとして『登録ユーザドメイン』クラス及び『登録
ユーザリポジトリ』クラスを抽出します。
(5) 当該ユースケースの機能を提供するサービスとして『ユーザ登録サービス』クラスを抽出します。
処理の流れは、下図のようになります。
ユーザ登録
サービス
登録ユーザ
リポジトリ
登録ユーザ
ドメイン
登録ユーザ
DAO
ドメイン生成()
登録ユーザドメイン
登録(登録ユーザエンティティ)
登録(登録ユーザエンティティ)
データベース登録
※ 単一のレコードに対する操作であっても、データベースに新しいレコードを追加する場合は、
リポジトリでドメイン生成を行います。
7
オブジェクト指向設計基礎講座
6.2. 複数のデータを操作するパターン
ここでは説明簡略化のため、ポータルサイトでログイン履歴取得操作が実行された場合、データベー
スのログイン履歴テーブルから複数件のデータを取得する仕様であると仮定します。
ユースケースで機能がこのように規定された場合、設計手順は次のようになります。
(1) データベーステーブルとして『ログイン履歴』テーブルを抽出します。
(2) ログイン履歴テーブルに対応するエンティティクラスとして『ログイン履歴』クラスを抽出
します。
(3) ログイン履歴テーブルに対応する DAO クラスとして『ログイン履歴 DAO』クラスを抽出します。
(4) ログイン履歴テーブルに対応するドメインクラスとして『ログイン履歴ドメイン』クラス及び
『ログイン履歴リポジトリ』クラスを抽出します。
(5) 当該ユースケースの機能を提供するサービスとして『ログイン履歴取得サービス』クラスを
抽出します。
処理の流れは、下図のようになります。
ログイン履歴
取得サービス
ログイン履歴
リポジトリ
ログイン履歴
DAO
取得()
取得()
データベース検索
ログイン履歴リスト
ログイン履歴リスト
※ 複数レコードに対する操作の場合、単一のデータを操作することがなければ、ドメインクラス
にはアクセスがありません。(リポジトリが直接 DAO を操作します)
8
オブジェクト指向設計基礎講座
6.3. まとめ
ユースケース分析から設計・実装までの流れをまとめると、次のようになります。
(1) ユースケースより、データベーステーブルを抽出する。
(2) ユースケースより、データベーステーブルに対する操作内容を抽出する。
(3) 上記(1)で抽出したデータベーステーブルに対応する、エンティティクラスを作成する。
(4) 上記(1)で抽出したデータベーステーブルに対応する、DAO クラスを作成する。
(5) 上記(1)で抽出したデータベーステーブルに対応する、ドメインクラスを作成する。
(6) 上記(1)で抽出したデータベーステーブルに対応する、リポジトリクラスを作成する。
(7) 上記(2)で抽出したデータベーステーブルに対する操作を、ドメインクラス、リポジトリクラス、
DAO クラスに実装する。どのクラスにどの操作を実装するかは、各クラスの役割(ロール)によ
って決定する。
※ ただしドメイン駆動を使ったこのような設計手法は、業務ロジックだけを集めた基幹システムの
構築にのみ有効です。画面も含めた設計を行う場合は、別途ロバストネス分析等の手法を用いる
必要があります。
7. ビジネスルールとカバレッジ
オブジェクト指向に関する書籍では、よくテスト駆動のことが書かれています。テスト駆動とは、実
装が正しいことを担保するためにテストプログラムを最初に作成し、実装したコードを必ずテストす
る手法で、通常全ての条件分岐に対してテストを割り当てます。
考えられる全ての処理ルート(条件分岐)にテストを配置し、実装の正確さを保証することで品質
を確保するというものなのですが、実際には全ての条件分岐にテストを配置するのは多大なコストが
かかります。
実装コード
テストコード
実装コード上の全ての条件分岐に、テストコ
ードをペアで作成する。
銀行などの金融関連のシステムでは絶対にミスは許されませんから、このような全ての条件分岐に
対応するテストは必須であるともいえますが、オブジェクト指向を行うあらゆるプロジェクトでテス
ト駆動を実装するのはコスト面の問題から難しいといえます。(テストとコードを一緒に作るだけな
らまだしも、クラス構成のちょっとした変更でもテストが大幅書き直しになってしまいますので、特に
メンテナンスコストがかかります)
9
オブジェクト指向設計基礎講座
このような問題を解消するためには、ビジネスルールの外部化が有効です。ビジネスルールとは、業
務ロジック上で行われるチェック処理を指すと考えていいでしょう。これをクラス化することにより、
カバレッジ確保を容易にします。
実例を見てみましょう。例えばメールアドレスをログイン ID とするポータルサイトで、ユーザ登録
を行う場合のチェックを考えてみます。
A.
オークションなどを行うサイトでは、氏名・住所・電話番号などを登録データとして必要とす
る場合も多いでしょう。まず『必須項目が全て入力されていること』というチェックが必要そう
です。
B.
メールアドレスをログイン ID としているため、重複するメールアドレスでの登録はできません。
『同じメールアドレスが登録されていないこと』というチェックも必要です。
C.
ポータルサイトによっては、同じユーザが複数のアカウントを取得できないようにしたいこと
もあるはずです。
『同じ氏名・住所・電話番号のユーザが登録されていないこと』というチェッ
クが必要な場合もありそうです。
まとめると、ユーザ登録時のビジネスルールは次のようになります。
ユーザ登録時のビジネスルール
必須項目が全て入力されてい
ること
同じメールアドレスが登録さ
れていないこと
同じ氏名・住所・電話番号の
ユーザが登録されていないこ
と
これを『ユーザ登録ビジネスルール』というクラスとし、このクラスで上図のチェック処理を実装し
ます。テストクラスは、ビジネスルールクラスに対して作成します。ビジネスルールクラスが操作する
主属性は、ドメインもしくはリポジトリから取得できるエンティティとなります。ストラテジパターン
やデコレータパターンによって、ビジネスルールが呼び出されるようにします。
10
オブジェクト指向設計基礎講座
クラス図は次のようになります。
UserRegistrationBusinessRule
PortalUserDomain
+check(PortalUser portalUser)
-entity : PortalUser
+register()
ドメイン駆動では全ての業務ロジックをドメイン層に記述します。ポータルサイトのユーザ登録と
いう処理があったら、ポータルユーザドメイン(PortalUserDomain)にユーザ登録(register)のメ
ソッドを作成します。ユーザ登録ビジネスルール(UserRegistrationBusinessRule)はドメインから
呼び出されるチェックロジックで、前述のようなチェックを行います。
ビジネスルールをクラスとして外部化することには、次のようなメリットがあります。
(1) ビジネスルールは最も変化しやすい部分であり、他の業務ロジックと分離しておくことでメンテ
ナンスが有利になる。(ビジネスルールのみを変更することで、他の実装に変更の影響を及ぼさ
ないようにすることができる)
(2) ビジネスルールを除けば、モデルクラスの処理はデータ編集とベースの参照・更新のみとなる。
(本質モデルのコードがすっきりする)
(3) ユースケースにあるチェックとの対応をとりやすく、ビジネスルールクラスのカバレッジを
100%にすることで、システムの機能として必要とされているチェックを全てクリアできる。
単体テストレベルで全ての条件分岐をテストするコードを書いてテスト駆動を実施するのは、工数
上の問題で困難をともないます。ビジネスルールの外部化といった工夫により、最も変更されやすいチ
ェックロジックの部分だけ切り出し、メンテナンスコストを下げる必要があります。
オブジェクト指向はデータとロジックが同じクラスにあることを利点とするため、通常このような
ロジックだけの分離は NG とされます。しかし本質モデルであるドメインクラスが CRUD+複数デー
タ処理のメソッドを多数持つ可能性があることを考えれば、1 クラスのコードを何千ステップにもし
ないために、こうした一部ロジックをデコレータパターン等で外部化することは十分考えられます。プ
ロジェクトの特性に応じた対応が求められます。
11