Strategyパターンの例
開発者の中には、デザインパターンを崇高な規格、理想ととらえている人がいます。デザインパターンをあまりに神聖視するがために、特に注目度の高い実装以外ではデザインパターンを使おうとしない開発者の姿も何度か見たことがあります。
しかしそうではなく、実際にはデザインパターンはごく頻繁に利用すべきものであり、標準的なプログラミング構造の1つとして積極的に使用していくべきです。パターンをあがめ奉ってはいけません。
別の言い方をすると、完璧なチャンスを待っていてはいけないのです。また、デザインパターンを恐れるべきでもありません。オリジナルの『Design Patterns』の書籍は手ごわい代物ですが、そこに載っているパターンの大半は、理解しやすく応用が簡単です。デザインパターンの多くは非常にシンプルで、あらためて見直すと、皆さん自身も実は数分おきにデザインパターンを使っていたということに気がつくかもしれません。Iteratorパターンは、知らず知らず使われているようなパターンの仲間に確実に入りますし、Template MethodやStrategyといったパターンも同様です。
Strategyパターンは、『Design Patterns』によると「アルゴリズムの集合を定義し、各アルゴリズムをカプセル化して、それらを交換可能にする。Strategyパターンを利用すると、アルゴリズムを、それを利用するクライアントから切り離して個別に変更できるようになる(Erich Gamma)」そうです。それほど手ごわい感じはしませんね。
デザインパターンについて覚えておくべき第一のことは、必要性がなければいけないということです。私がソリューション、またはその一部のコードを最初に書くときは、実装をなるべくシンプルにするように心がけます。普通は、パターンのことさえ思い浮かべません。現行の、そして既存のソリューションに新しいコードを追加する際は、込み入ったコード記述部分を単純化するため、または単にコードをよりテストしやすいものにするために、冗長性をなくす方法を探します。こうした修正を行おうとするとき、そのための最良のアプローチは既知のデザインパターンであると気づくことがよくあります。そこから、最終目標に向けて自分自身を導く手助けのために、デザインパターンの知識を使用していきます。
本稿では、Strategyパターンから派生する1つの事例として、SQLジェネレータの一部を作成していきます。基本的な考え方は、リレーショナルテーブルと列に関するメタデータが与えられ、ジェネレータが対応するSQL文字列を返すというものです。なるべくシンプルに保つという発想から、ここでは挿入される日付の列についてのVALUES句を生成する部分にもっぱら重点を置くことにします。
さて、仮想の依頼主によると、このSQLジェネレータを使用するアプリケーションは、MySQLをサポートしている必要があります。このSQLジェネレータには、MySQL用の挿入値を生成する機能が必要です。MySQLでは、日付が「年-月-日」の形式となっていて、月と日はそれぞれ2桁の数字を使います。
'2007-07-15'
以下が私の書いた、MySQLをサポートするのに必要な基本機能を指定するテストコードです。
import static org.junit.Assert.*; import java.util.*; import org.junit.*; public class DateColumnTest { private static final String NAME = "name"; private DateColumn column; @Before public void initialize() { column = new DateColumn(NAME); } @Test public void create() { assertEquals(NAME, column.getName()); } @Test public void insert() { assertEquals("'2007-07-15'", column.insertString(DateUtil.createDate(2007, Calendar.JULY, 15))); } }
DateColumnTest
のコードでは、シンプルな日付ユーティリティメソッドを使用しています。以下がそのコードです。
import java.util.*; public class DateUtil { private static final Calendar calendar = Calendar.getInstance(); public static Date createDate(int year, int month, int dayOfMonth) { calendar.set(year, month, dayOfMonth); return calendar.getTime(); } }
MySQLソリューションの実装は、皆さんもお察しのとおり、大変シンプルです。
import java.util.*; public class DateColumn { private String name; public DateColumn(String name) { this.name = name; } public String insertString(Date date) { return String.format("'%1$tY-%1$tm-%1$td'", date); } public String getName() { return name; } }
このMySQL固有のコードを組み込んで、完了したイテレーション作業の一部として納品しました。