Before/Afterパターン
Before/Afterパターンとは
GoF以外のデザインパターンの連載も、いよいよ今回で最終回となります。これまでの連載では、デザインパターンの必要性やNullObcectパターン(第1回:http://thinkit.jp/article/926/1/)、Object Poolパターン(第2回:http://thinkit.jp/article/934/1/)について詳しく紹介してきました。
また、前回(http://thinkit.jp/article/941/1/)は一部内容を変更して、デザインパターンを勉強するために厳選した書籍を紹介しました。デザインパターンに興味をもたれた方は、ぜひ押さえておくとよいのではないでしょうか。
全3回と少々駆け足でしたが、今回は、Before/Afterパターンについて解説していきます。Before/Afterパターンは、以下の順番でメソッドを実行させるためのパターンです。
before()→method()→after()
・before:メソッドを実行する前の事前の準備処理
・method:本体処理
・after:メソッドを実行した後片付けをおこなう処理
このパターンは、多くの実装例(詳しくは後で説明します)で見ることのできるものであり、オブジェクト指向以前からも用いられてきました。Before/Afterパターンをもっともシンプルに実装するには、以下のようになります。
before(); method(); after();
しかしながら、上記の例では、method()で例外が発生した時に事後処理がおこなわれません。
そこで、method()で例外が発生しても、必ずafter()が実行されるようにしたのが下記のコーディング例です。
before();
try {
method();
}
finally {
after();
}
Before/Afterパターンの適用可能性
Before/Afterパターンは、実際のシステムでもよく見かけられるポピュラーなパターンですが、このパターンを利用する動機は場面によって異なります。以下ではその代表的な場面を説明します。
・変数の初期化/値設定
オブジェクトのインスタンス変数の初期化や値の設定
・外部リソースの接続/切断
外部リソース(データベース、ネットワーク通信等)との接続、切断処理
・契約プログラミング
Before/Afterパターンに関連して、契約プログラミングというものがあります。契約プログラミング(Programing By Contract)とは、プログラムコードの中に、プログラムが満たすべき仕様について記述をすることで、設計の安全性を高める技法です。この技法はもともとEiffelで導入されましたが、現在ではJava等の代表的な言語でも利用することができます。
契約プログラミングでは、事前条件、事後条件、不変条件という3つの利用条件があり、メソッドの開始時(Before)と終了時(After)にチェックを行います。例えば、メソッドの呼び出す側が、保障すべき条件(事前条件)をメソッドの開始時にチェックし、呼び出されたメソッドの側で保証すべき条件(事後条件)をメソッドの終了時にチェックします。こうした、契約プログラミングの利用条件を記述する際にも、Before/Afterパターンを利用することができます。
・マルチスレッド
現在では、マルチコアやマルチプロセッサを持つコンピューターが増えてきた結果、マルチスレッド(スレッドという処理単位が複数生成され、並行して処理が行われること)を前提としたプログラミングが重要になってきています。こうした、マルチスレッドプログラミングでは、共有データへのロックの取得/解放など、マルチスレッド特有の事前処理/事後処理を実装する際に、Before/Afterパターンがよく用いられています。
マルチスレッドで必要となるプログラミングテクニックの詳細やパターンについての説明はここでは割愛しますが、興味のある方は、3ページ目で紹介している参考文献をぜひ読んでみてください。
関連するパターン
前ページで説明したように、Before/Afterパターン自体のコーディングはとてもシンプルですが、適用するクラスやオブジェクトの数が多いと、同じような記述をたくさん行うことになり、後々のメンテナンスが大変です。
保守性を高める一方で、将来の変化に柔軟に対応できるようにBefore/Afterパターンを適用するためには、以下のように、ほかのパターン(GoFパターン)と組み合わせることが有効です。
・Template Methodパターン
Template Methodパターンは、スーパークラス(図2のAbstractクラス)にTemplate Method(処理の枠組みとなるメソッド)を定義しておいて、詳細の実装はサブクラス(図2のConcreteクラス)に記述するパターンです。
このTemplate Methodの中にBefore/Afterパターンを記述し、サブクラス側でbefore()、method()、 after()を実装させることによって、Before/Afterパターンを簡単なフレームワークで実現することができます(図2の左側)。
メソッドのスコープについては、Templateメソッドはpublicですがそれ以外はprotectedになっているので、クライアント側からはTemplateメソッドだけが見え、Before/Afterパターンに従ってサブクラスの実装が呼び出されるようになるのです。
Adaptorパターン
新しいソフトウエアを作る場合において、Before/Afterパターンをたくさんのクラス・オブジェクトに適用するのであれば、Template Methodパターンを使って設計することが有効です。
ただし、既存のアプリケーションの拡張や、ほかから提供されたAPIを利用する場合において、Before/Afterパターンを後から適用するような場合には、Adaptorパターンのほうが向いています。
Adaptorパターンでは、既存の実装(図2のAdapteeクラス)に対して、新たにAdaptorクラスを追加します。このAdaptorクラスは、既存の実装を覆って隠してしまう、一種のラッパークラスです。
Adaptorクラスには、before()、targetMethod()、after()の3つのメソッドがあり、targetMethod()の中にBefore/Afterパターンを記述します。これにより、クライアント側からはtargetMethod()だけが見えた状態で、既存の実装(Adaptee)に対してBefore/Afterパターンを適用することができるのです。
Before/Afterパターンの利用例(JUnit)
前述したように、Before/Afterパターンを適用した例はいろいろなところで見かけることができます。例えば、身近なところでは、Java用のユニットテスト(単体テスト)フレームワークとして有名な"JUnit"にも、Before/Afterパターンに相当する機能が提供されています。
JUnitでは、Junit.framework.TestCaseを継承して、テストクラスを記述することができるのですが、Before/Afterパターンに相当するメソッドとして、setUpメソッドとtearDownメソッドをオーバーライドすることができます。
これらのメソッドは、テストケースの実行前/実行後に毎回呼び出されるので、テストケース実行前の共通的な初期化、テストケース実行後の共通的な終了処理を実装するのに用いられます。
TestCaseクラスの動作を確認するために、簡単なサンプルを動かしてみましょう。
・コードサンプル
import junit.framework.TestCase;
public class TestSample extends TestCase {
public void setUp() {
System.out.println("Before");
}
public void testCase1() {
System.out.println("TestCase1");
}
public void testCase2() {
System.out.println("testCase2");
}
public void tearDown() {
System.out.println("After");
}
}
・実行結果
>Before
>TestCase1
>After
>Before
>testCase2
>After
最後に
今回紹介したように、GoFのパターン以外にも重要なパターンはたくさん存在します。本連載では、ボリュームの都合によりそのいくつかしか取り上げることができませんでしたが、そのほかのパターンについて知りたい方は文末の参考文献などをぜひ読んでみてください。
これまで紹介してきたデザインパターンと呼ばれるものは、決して思いつきで発明されたのでなく、先輩たちの時代から良い設計を積み重ねた結果の財産として、現在に至っているのです。
先輩たちの時代の設計が、こうして広く知られるようになってきたように、いつか皆さんの良い設計・実装が次の時代の新しいパターンになっていくのではないでしょうか。この連載が、その役に立つことを楽しみにしています。
【参考文献】
ダグ リー (著), 松野 良蔵 (翻訳)
Javaスレッドプログラミング―並列オブジェクト指向プログラミングの設計原理
翔泳社刊 ISBN 978-4881359181
結城 浩 (著)
増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編
ソフトバンククリエイティブ刊 ISBN 978-4797331622