Strategyパターン

とあるきっかけで、Strategyパターンとはなんなのか、考えてみたくなった。Strategyパターンはオブジェクト指向でコードを書いていると随所に見られるパターンだからだ。例えばWebサイトの入力チェックを行うValidatorなんかは、Fieldオブジェクトにいくつか持たせられる形で実装しておく事が多い。例えば下記のような形で実現されていないだろうか。

f:id:kompiro:20130929194340p:plain

会員登録のページを想像するとわかりやすいと思うのだけど、ページの中に複数のフィールドがあり、それぞれのフィールド毎に入力チェックをしなければならないとする。上図のように入力チェックのアルゴリズム毎にクラスを用意しておき、それぞれのフィールドに必要な形で設定していく事ができる。この形の優れているところは、入力チェックのアルゴリズムを再利用できるところだ。会員登録のような機能は、様々なサイトで利用される機能だし、どれも似通ったものだからだ。

そのアルゴリズムを、上図のEmptyValidatorのように、空文字かどうかチェックするだけのValidatorを用意しておけば、必須チェックかつEmailのフォーマットをチェックすると言った、ユーザーを識別用のEmailの入力フィールドを作成するなんてことも簡単だ。

さて、デザインパターンの原典であるGoF本によると、Strategyパターンの目的は

アルゴリズムの集合を定義し、各アルゴリズムをカプセル化して、それらを交換可能にする。Strategyパターンを利用することで、アルゴリズムを、それを利用するクライアントからは独立に変更することができる。

とある。上記のように、入力チェックはアルゴリズムをカプセル化して交換可能になっているので、Strategyパターンが見受けられる。Strategyパターンは別名Policyパターンと呼ばれる。Policyと名付けられるクラス群も同様に交換可能な形で実現されることが多いから、そういう別名がつけられているのだと思う。

最近は、テストコードを書くために、mockで差し替えられるようにある処理の単位でクラスを作成し、テストコードからのみ差し替えられるよう、defaultスコープのsetterを用意する事もよくやる。SWTとかSwingとかのアプリは、警告ダイアログを表示することがあるけど、これをそのまま表示すると、テスト時にダイアログが表示されてしまう。それが邪魔なので、テストコードから利用するときは、差し替えられるようにしておくのだ。

Erich Gammaによると、デザインパターンとは、オブジェクト指向プログラミングの上級実装者がコードによく表現する構造等をパターンとしてまとめたものだ。InfoQにErich Gammaがデザインパターン等について語ったインタビューによると

私はEclipseを発展させている間、実際にEclipseアーキテクチャーをパターンを使って説明したのは本当に楽しかったです。
私が説明した、「Contributing to Eclipse:(和名:Eclipseプラグイン開発 デザインパターン×テスト駆動開発)」では、あるチャプターで…、あ、その本の共著もKent Beckでしたね。私はEclipseアーキテクチャについて、パターンを使って説明することに挑戦しました。
それは私にとってとても良いテストとなりました。なぜならEclipseはまだ全然、ある種の「私達はパターンを使っている」と言ってきたわけではありませんからね。それは開発者たちの経験からできたものなのです。
彼らはオブジェクトの設計技術についてとても理解していて、だから私は最後のほうは、もし、あなたがEclipseの中にあるアーキテクチャや設計について探してみると、どれだけパターンによって、キーとなる部分を説明できると思いますか?それは私にとってちょっとした喜びでしたし、幾つかのよい感じの対象を見つけることができました。

とある。

XUnit Test Patternsでちなみに、GoF本が書かれたのは1995年。JUnitが産まれたのは2000/12/3なので、たぶんユニットテストが一般的になる前。テスト時にモックオブジェクトで差し替えられるようにするなどという話はまだなかっただろう。(テスト時にモックオブジェクトで一部処理を差し替えられるようにするのは、XUnit Test Patternsでまとめられている。というか、それで知った。)*1

Strategyパターンというのは、コードを書く時にある部分だけ別のクラスに委譲し、入れ替えられるようにする時によく見られる構造にだ。テストコードを書く時にも助けになるパターンなので、覚えておくといいと思う。

*1:自動テストは、既にオブジェクト指向が産まれる前から取り組まれている。そのコードをユニットテストと呼ばれていたか、調べ切れなかったが、テスト用のドライバと呼ばれていた。また、テスト用のスタブを作る事で、開発前のコードでもテストできるように先人は取り組んでいた。ただ、ここで述べたかったのは、Strategyパターンを使って、テスト時にテスト用の処理を行うように置き換える事は有効ということでした。