参考リンク
- 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を書かなければなりません.図で表すと以下のような具合になります.
<img src="http://53ningen.com/wp-content/uploads/2014/07/L-1.png" l-1" width="538" height="560" class="aligncenter size-full wp-image-686" />
このような状況に上手く対処するために 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 のクラス図を示しておきます.
<img src="http://53ningen.com/wp-content/uploads/2014/07/L-2.png" l-2" width="428" height="304" class="aligncenter size-full wp-image-687" />
時間経過に伴って機能が拡張されていくバージョンアップの過程と,実装タイプのバリエーションを豊富に広げる品揃えの充実具合を,別個に分けて,整理して管理できる(GoF の 23 のデザインパターンを,Java で活用するための一覧表より)
Java8 での機能と実装の追加について考えてみた.
この部分については個人的に思いついた内容なので,実際に良い方法なのか微妙なところですが,とりあえず書いておきます.Java8 ではインターフェースがデフォルト実装を持てるようになったため,先の例ででてきたSorterを抽象クラスではなくインターフェースとして定義しておけば,「実装の拡張」はもちろん,「機能の拡張」もすっきりおこなえるかなと思いました.ソートにかかる時間を表示する timeSort 機能を追加したあとのクラス的にはこんな具合になると思います.
<img src="http://53ningen.com/wp-content/uploads/2014/07/L-3.png" l-3" width="538" height="290" class="aligncenter size-full wp-image-688" />
現時点でこの方法が抱えている問題は,Sorterが抽象クラスではなくインターフェースになったので状態(プロパティ)を持てなくなってしまったという点だと考えていますが,どうでしょうか.
Pinned Articles
About
ウェブ界隈でエンジニアとして労働活動に励んでいる @gomi_ningen 個人のブログです
Tags
JavaScript
PowerShell
kibana
elasticsearch
fluentd
nginx
イベント
五十嵐裕美
村川梨衣
logrotate
IoT
Scala
Java
C言語
iputils
ICMP
WUG
mastodon
Swift
AWS
Clock
Windows
アーキテクチャ
PoEAA
iOS
DeviceFarm
プログラミング言語
OS
StepFunctions
Lambda
Serverless
terraform
ポエム
RHEL
ネットワーク
GraphQL
CloudWatch
Linux
Coreutils
network
nc
telnet
LinuxKernel
fpinscala
ELB
IAM
AppSync
EFS
Gradle
english