Strategyパターンの事例と本連載のまとめ
定額給付金のシミュレーションプログラムでStrategyパターンを解説
「事例で学ぶデザインパターン」最終回となる今回は、定額給付金のシミュレーションプログラムを事例に、GoFのデザインパターンの1つであるStrategyパターンを取り上げます。
Strategyパターン(図1-1)はふるまいに分類されるパターンです。Strategyとは「戦略」という意味で、一言で言うとアルゴリズムのことを指しています。Strategy役はアルゴリズムを利用するためのインターフェースを規定します。そしてConcreteStrategy役はStrategy役のインターフェースで具体的なアルゴリズムを実装します。このパターンはContext役から利用するアルゴリズムを独立させることで、そのアルゴリズムを簡単に交換できるようになります。
例えば、名前を一覧表示するプログラムがあるとします。そのプログラムは昇順や降順で名前を並べて表示できます。この場合、名前の一覧表示プログラムがContext役であり、名前をソートするアルゴリズムがStrategy役になります。そして名前を昇順や降順で並び替える、具体的なソートのアルゴリズムはConcreteStrategy役になります。Context役は、昇順や降順で名前を並び替えるアルゴリズムを交換することで目的を果たします。
定額給付金のシミュレーションプログラムを作成する
定額給付金は、皆さんもご存じのように日本の景気対策の1つとして現在実施している事業です。筆者も先月手続きを済ませたところです。
筆者なりに定額給付金が給付される仕組みを理解するために、図1-2、図1-3のような定額給付金の概念モデルとそのオブジェクト図を作成しました。今回はその概念モデルから定額給付金を給付する仕組みをシミュレーションするプログラムを設計します。そしてその設計を行いながら、デザインパターンを活用するポイントについて解説します。
なお定額給付金の詳細については、総務省の「定額給付金について(http://www.soumu.go.jp/teigakukyufu/)」を参照してください。
■定額給付金 概念モデルの説明
今回作成した定額給付金の概念モデルは、次の制約・前提条件をもとに作成しています。
●制約・前提条件
1)住民票の概念は割愛(住民が存在する=住民登録されているとする)
2)外国人登録原票の概念は割愛
3)世帯の概念は割愛(全員が世帯主)
4)銀行は1つとし、簡易的のものとする
5)住民は1名以上存在することとし、銀行の預金口座を必ず1つ持っている
6)住民の年齢は基準日(平成21年2月1日)をもとに設定する
7)役所は1つとし、給付担当者は1名以上存在する
8)給付担当者は、次の条件で住民に給付する
住民の年齢が18歳以下または65歳以上の場合20,000円、それ以外は12,000円。
9)給付方式は窓口申請方式(口座振り込みにより受給)、窓口現金受領方式(現金受給)のみ
10)未給付、給付済みのステータスは管理しない
以上の制約・前提条件をもとに、定額給付金の給付に関する処理を中心に分析・設計を進めていきます。
1)住民は窓口申請方式か窓口現金受領方式の給付方式を選択し、役所に定額給付金の申請書を提出する
2)役所は受け取った申請書をもとに給付担当者に指示を出す
3)給付担当者は給付条件を確認し、給付金額と給付方式を決定して住民に給付する
●概念図についての補足
住民: 給付金を受け取る資格を持った住民。
給付金申請書: 役所で給付関連の手続きを行う際の申請書。
役所: 地方自治体が住民に対してサービスを提供する場所。
給付担当者: 役所の職員。給付作業を担当する。
給付: 給付担当者が住民に給付金を支給する。
給付方式: 給付金を支給する方法。
銀行: お金を預けることができる場所。複数の口座を持つ。
口座: 住民ひとりひとりの預金を管理する口座。
預金通帳: 開設した口座の入出金の状況を記録するもの。今回は残高のみ管理する。
何が変動要素なのか考える
今回は、役所が住民に給付金を支給する仕組みをシミュレーションするプログラムを作成します。このプログラムは、定額給付金以外の給付金の給付にも柔軟に対応できるように設計します。
柔軟に対応できる設計を行うには、まずシステム要求の中に潜む「普遍要素」と「変動要素」を知ることが重要です。普遍要素はシステム要求の中で時間の経過や環境の変化に影響を受けないものを指します。
一方、変動要素はその逆で、システム要求の中で時間の経過や環境の変化に影響を受けるものを指します。簡単に言うと要求の中でコロコロと変わりそうな要素のことです。その変動要素がわからなければ設計する側は何も考慮することができないため、柔軟に対応できる設計を行うことができません。
今回は、次の3つを変動要素として設計を行います(図2-1)。
●給付金申請書……生成の問題
給付金申請書は定額給付金申請書の1種類ですが、地方自治体によってさまざまな給付金申請書が存在する場合があります。給付金申請書の種類が後で増えても、ほかに影響しないように後で給付金申請書の種類を決定できる仕組みが必要です。
●給付担当者……ふるまいの問題
給付担当者は定額給付金給付担当者だけですが、地方自治体によってはさまざまな給付金申請書が存在する場合があります。その給付金申請書ごとに処理する担当者や体制が異なる可能性があります。ほかに影響しないように後で給付担当者の責務や体制を柔軟に変更できる仕組みが必要です。
●給付方式と給付……ふるまいと生成の問題
給付方式は給付担当者が住民に給付金を給付する方法で「窓口申請」と「窓口現金受領」の2種類があります。給付担当者は給付方式の中から1つ選択して、住民に給付金を給付します。給付金申請書の種類によっては給付方式が増減するかもしれません。ほかに影響しないように後で給付方式の種類を交換できる仕組みが必要です。
変動要素が抱える問題を解決する
変動要素が抱える問題について次のように解決します(図2-2)。
●給付金申請書(BenefitSheet)…… Factory Method
給付金申請書(BenefitSheet)を作成する役割を持つクラス(BenefitSheetFactory)を追加し、そのクラスには第3回で紹介したFactory Methodパターンを適用します。
Factory Methodパターンを選択した理由は、給付金申請書の生成の仕組みと給付金申請を決定する仕組みを分離することが実現できるからです。
その結果、給付金申請書の種類を後から決定できるようになります。
今回は、定額給付金申請書ファクトリーから定額給付金申請書を作成します。
●給付担当者(AbstractIssueStaff)……Chain of Responsibility
給付担当者には第4回(http://thinkit.co.jp/article/938/1/)で紹介したChain of Responsibilityパターンを適用します。Chain of Responsibilityパターンを選択した理由は、給付金申請書の種類に応じた責務を持つ給付担当者を柔軟に追加・変更できる仕組みが実現できるからです。
今回は、次の責務を持つ定額給付金の給付担当者を作成します。
・定額給付金給付担当者(m歳以下担当)
給付条件:申請者の年齢が18歳以下なら給付する
給付金額:20,000円
・定額給付金給付担当者(m歳~n歳担当)
給付条件:申請者の年齢が19歳~64歳なら給付する
給付金額:12,000円
・定額給付金給付担当者(m歳以上担当)
給付条件:申請者の年齢が65歳以上なら給付する
給付金額:20,000円
●給付方式(Issue Algorithm)と給付(Issue)……StrategyとFactory Method
給付方式の部分にStrategyパターンを適用します。Strategyパターンを選択した理由は、給付方式の1つ1つが異なったアルゴリズムであり、そのアルゴリズムを交換できる仕組みが実現したいからです。また給付(Issue)を作成する役割を持つクラス(IssueFactory)を追加し、そのクラスにFactory Methodパターンを適用します。Factory Methodパターンを選択した理由は、給付金申請書の給付方式の内容に合った、給付方式のアルゴリズムを持つ給付のインスタンスを生成するためです。
その結果、給付方式のアルゴリズムの交換が容易になり、給付金申請書の給付方式に合ったアルゴリズムを持つ給付のインスタンスが生成できるようになります。
今回は、「窓口申請」と「窓口現金受領」の2つの給付方式を用意します。
最後は解説が駆け足になりましたが、今回の事例はほんの一例です。ほかにもよいモデルや解決方法があるかもしれません。読者の皆さんも同じテーマでモデリングして、モデルに潜む変動要素を探し出してデザインパターンの適用にチャレンジしてみてください。
なお今回は本事例のサンプルコード(example-1.0.0-src.zip)をご用意しましたので、こちらからダウンロードしてください。
デザインパターンの活用ポイント
これまで紹介したパターンも含めて、デザインパターンには次の共通する設計指針があります。
・変動要素の分離
・クラス継承より、オブジェクトコンポジションの活用
・インターフェースの活用
これらの指針はデザインパターンだけに限らず、オブジェクト指向設計の定石とも言えるものです。再利用を考えた場合、変動要素を持つクラス間の結合度はできるだけ弱くする必要があります。よって、安易なクラス継承は好まれず、コンポジションによるオブジェクトの合成や、クラスとクラスの間に間接層としてインターフェースを追加することで、クラス間の結合度を弱くします。
これらの指針を十分に理解することがデザインパターンを習得する近道になります。
変更に強い設計や既存実装のリファクタリングを行う場合、何が変動要素なのかよく知ることが重要です。そして変動要素の抱える問題に対する解決法が必要になります。今回はGoFのデザインパターンの中から問題に対する解決法(図3)をまとめましたので、参考にしてデザインパターンを活用してください。
最後に
今回でこの連載は最後になりますが、この5回の連載で23種類のGoFのデザインパターンの中から次の8つを紹介しました。
・第1回 Template Method(ふるまい)
・第2回 Observer(ふるまい)
・第3回 Adapter(構造)
・第3回 Factory Method(生成)
・第4回 Composite(構造)
・第4回 Command(ふるまい)
・第4回 Chain of Responsibility(ふるまい)
・第5回 Strategy(ふるまい)
この連載で紹介できなかったパターンも含めて、どのパターンも目的や構造は非常に小さく単純なものばかりです。しかし、中にはパターンの構造が同じものもいくつか存在しているため混乱することもあるでしょう。そんな場合は、パターンの目的や動機、適用可能性をしっかり読み直してパターンの着眼点を理解してください。そうすれば、なぜ同じ構造になるのか混乱せずに理解できるはずです。
またデザインパターンを学習する方法の1つとして、連載の中で紹介した事例のようにオープンソースソフトウエア(以下、OSS)のソースコードを読んでみることをお勧めします。OSSの中で何を実現するためにどのデザインパターンが使われているかを理解することで、デザインパターンがもたらすメリットや、活用する場面を整理できるからです。もし、実践でデザインパターンをうまく活用できないような経験がある場合は、一度チャレンジしてみてください。
要求を正しく理解して、ソフトウエアの基本構造をしっかり設計することで、仕様変更による影響を最小限にとどめることができます。デザインパターンは、ソフトウエアの基本構造を支える知識の1つとして非常に有効です。またデザインパターンは、既存の実装をリファクタリングする際にも有効です。これを機会に開発の現場でデザインパターンを活用できているか振り返ってみるのもよいかもしれません。
最後になりますが、この連載が開発の現場に携わるエンジニアの方々に少しでもお役に立てれば幸いです。それでは、またどこかでお会いしましょう!
【参考文献】
Erich Gamma, Rechard Helm, Ralph Jonson, John Vlissides『オブジェクト指向における再利用のためのデザインパターン』ソフトバンククリエイティブ(発行年:1999)
結城 浩『Java言語で学ぶデザインパターン入門』ソフトバンクパブリッシング(発行年:2001)
「総務省 - 定額給付金について」(http://www.soumu.go.jp/teigakukyufu/) (アクセス:2009/04)