参考リンク
- GoFの23のデザインパターンを,Javaで活用するための一覧表 (パターンごとの要約コメント付き)
- 9. Bridge パターン
- Java8のインタフェース実装から多重継承とMixinを考える
- Java8で最もインパクトのある構文拡張、デフォルトメソッド
機能と実装の違い
ある数列[1,3,2,5,4]をソートしたいとします.このときソートの方法は何通りかあります.このとき「ソートをする」ということが機能にあたります.そして「ソートをする方法」,たとえばクイックソートやマージソートなどが実装にあたります.クラスを拡張しようとするときには,具体的には「機能の拡張」と「実装の拡張」のいずれかであることが多いです.
Bridge Patternが必要になる状況例
TECSCOREにわかりやすい例が載っていたので,それに添ってBridgeパターンが必要になるシチュエーションを見てみます.ソート機能を持つ抽象クラスSoter
に対して,実装クラスQuickSorter
とBubbleSorter
を以下のように作成したとします.機能はSoter
,実装はQuickSorter
, BubbleSorter
に分離されていることに注意します.
public abstract class Sorter {
public abstract void sort(Object obj[]);
}
public class QuickSorter extends Sorter {
public void sort(Object obj[]){
// クイックソートで obj[] をソートする
}
}
public class BubbleSorter extends Sorter {
public void sort(Object obj[]){
// バブルソートで obj[] をソートする
}
}
現状のコードに新しい「実装」を増やすことは容易いです.単にSoter
をextendsした実装クラスを書けば良いだけだからです.しかしながら新しい「機能」を増やすためにはどうしたら良いでしょうか.ためしにソートに加え,それにかかった時間を表示する機能を追加したい場合を考えてみます.するとコードは以下のようになります.
public abstract class TimerSorter extends Sorter {
public void timerSorter(Object obj[]){
long start = System.currentTimeMillis();
sort(obj);
long end = System.currentTimeMillis();
System.out.println("time:"+(end - start));
}
}
ソートの実装自体は先ほど実装してあるQucickSort
, BubbleSort
クラスを使いたいとします.しかしながらよくよく考えてみるとTimeSorter
にそれらの実装を与えることができません(Java1.7以下での話?).そこで残念ながらそれらのTimeSorter
に対応した実装クラスQuickTimeSorter
とBubbleTimeSorter
を書かなければなりません.図で表すと以下のような具合になります.
このような状況に上手く対処するためにBridge Patternが用いられます.
Bridge Pattern
Bridge Patternでは実装の部分を別の階層に切り離すことによって,これまでに見てきた例のような問題を解決します.まずはコード例を見てみます.
public class Sorter {
private SortImpl sortImpl;
public Sorter(SortImpl sortImpl) {
this.sortImpl = sortImpl;
}
public void sort(Object obj[]) {
sortImpl.sort(obj);
}
}
public abstract class SortImpl {
public abstract void sort(Object obj[]);
}
public class QuickSortImpl extends SortImpl {
public void sort(Object obj[]) {
// クイックソートで obj[] をソートする
}
}
public class BubbleSortImpl extends SortImpl {
public void sort(Object obj[]) {
// バブルソートで obj[] をソートする
}
}
このように機能を実現するための方法がSortImpl
に委譲
されているため,実装の追加はもちろん,機能の追加は容易になります.まとめとしてBridge Patternのクラス図を示しておきます.
時間経過に伴って機能が拡張されていくバージョンアップの過程と,実装タイプのバリエーションを豊富に広げる品揃えの充実具合を,別個に分けて,整理して管理できる(GoFの23のデザインパターンを,Javaで活用するための一覧表より)
Java8での機能と実装の追加について考えてみた.
この部分については個人的に思いついた内容なので,実際に良い方法なのか微妙なところですが,とりあえず書いておきます.Java8ではインターフェースがデフォルト実装を持てるようになったため,先の例ででてきたSorter
を抽象クラスではなくインターフェースとして定義しておけば,「実装の拡張」はもちろん,「機能の拡張」もすっきりおこなえるかなと思いました.ソートにかかる時間を表示するtimeSort機能を追加したあとのクラス的にはこんな具合になると思います.
現時点でこの方法が抱えている問題は,Sorter
が抽象クラスではなくインターフェースになったので状態(プロパティ)を持てなくなってしまったという点だと考えていますが,どうでしょうか.