状況・文脈(context)によって動的に振る舞いを変えたいときの定石がStrategy Patternです.
たとえば各OS向けに文字列を出力するTextPrinter
クラスがあるとします.
ところが各OS標準で用いられる改行コードはことなるのでその部分についての振る舞いをOSによって変えなければなりません.
以下はこういう状況のときにありがちなコード例です.
public class TextPrinter {
private OSType os;
private String printNewLineChar() {
if(os == OSType.WINDOWS)
return //CR+LF
if(os == OSType.MAC)
return //CR
if(os == OSType.UNIX)
return //LF
return null;
}
}
往々にしてif文の嵐になります.そこで改行コード出力のふるまいだけを抜き出して,オブジェクトとして扱ってしまおうというのがStrategy Patternになります(言い過ぎ?).どの環境下でのふるまいも共通して「改行コードを出力する」という責務を持っているのでインターフェースを決めておくと便利です.今インターフェースCompositorを定義し,その後に各々の環境に応じた実装をしていくと良いです.
interface Compositor {
pubic String printNewLineChar();
}
public class WindowsCompositor {
@Override
public String printNewLineChar() {...};
}
public class MacCompositor {
@Override
public String printNewLineChar(){...};
}
public class UnixCompositor {
@Override
public String printNewLineChar(){...};
}
public class TextPrinter {
privte Compositor compositor;
pubic TextPrinter(Compositor compositor) {
this.compositor = compositor
}
public String printNewLineChar() {
return compositor.printNewLineChar();
}
}
このようにスッキリしました.今やったことを抽象化したStrategy Patternのクラス図は以下のようになります.
【参考:GoF本での定義】アルゴリズムの集合を定義し、各アルゴリズムをカプセル化して、それらを交換可能にする。
Strategyパターンを利用することで、アルゴリズムを、それを利用するクライアントからは
独立に変更することができるようになる。アルゴリズム実装のための専用オブジェクトを複数作っておき,その中から使うものだけを動的に選んで実行する。
ある程度複雑なアルゴリズムになると,ふつうのプログラマであれば,その部分を切り出して集約するだろう。また,他のアルゴリズムに置き変わった時に備えて,互換性も持たせておくだろう。なので,あまり新規性を感じないパターンに思えるかもしれない。とはいえ,アルゴリズムの交換可能性を増すために,共通の基底(または共通のインタフェース)を持たせているという点は注目。(GoFの23のデザインパターンを,Javaで活用するための一覧表より)
Bridge PatternとStrategy Patternの違い
よくわからなかったので,GoF本の適用可能性の欄を参照しました.
- Bridge Pattern(構造に関するパターン)
- 抽出されたクラスとその実装を永続的に結合することを避けたい場合.
- 抽出されたクラスとその実装の両方を,サブクラスの追加により拡張可能にすべき場合
- 抽出されたクラスの実装における変更が,クライアントに影響を与えるべきではない場合
- 複数オブジェクトの間で実装を共有したい場合
- Strategy Pattern(振る舞いに関するパターン)
- 関連する多くのクラスが振る舞いのみ異なっている場合
- 複数の異なるアルゴリズムを必要とする場合.
- アルゴリズムが,クライアントが知るべきではないデータを利用している場合.
- クラスが多くの振る舞いを定義しており,これらがオペレーション内で複数の条件文として現れている場合.
ここから察するに,Bridge Patternは継承より委譲を使うことにより,インターフェースとその実装の結合を弱め,「機能」と「実装」を柔軟に拡張できる構造を作りたいときに使うパターン.そしてStrategy Patternは状況に応じ振る舞いが変わるような状況下でその振る舞いの部分を切り出し,クラスの肥大化・複雑化を避けたり,あるいはクラスと振る舞いの結合を弱めるために使われるのではないかと思いました.間違いがあったらご指摘いただけるとありがたいです.