「Bridge」という英単語は、「橋」を意味します。
このパターンは、以下で説明している「1, 2」の架け橋を提供するパターンです。
まず、継承の目的について考えてみます。継承の目的としては、主に次の2つが考えられます。
次は、この「1, 2」の継承関係が発達していくと、どういう問題が発生するかについて説明したいと思います。
下図を見てください。
抽象クラスAと、Aを継承し抽象メソッドを実装したクラスA1・A2の下図の関係があるとします。
上図状態のクラス関係に、抽象クラスAへの機能追加のため、クラスABを追加したとします。(下図参照)
この場合、クラスABからは、クラスA1・A2の実装メソッドをそのまま使用することができません。(Aを継承しているので、抽象メソッドのインタフェースは存在するが、クラスABの実装がない)
そこで、下図の様にA1・A2と同じ実装内容のクラスA1'・A2'を、クラスABのサブクラスとして追加しました。
これでひとまずクラスABからも、クラスA1'・A2'の実装メソッドを使用できるようになりました。
が、またまた今度は、クラスABに機能を追加しなくてはいけなくなったので、クラスABCを追加しました。
そのため、クラスA1''・A2''を追加しました・・・・。
この様に、クラスA(AB)に機能を追加しようと思うと、そのサブクラス(機能実装)まで追加しなければなりません。つまり、機能を追加する度に、その実装クラス(A1、A2)まで追加していかなければならなくなります。(機能追加クラス(1.の継承関係)数 × 実装クラス(2.の継承関係)数分のクラスを作成しなければならなくなる)
この問題を解消してくれるのが「Bridge」パターンです。
下図を見てください。
この様に機能実装関係のクラスを、クラスAに保持させる(架け橋を作る)事により、機能追加しても実装関係のクラス階層には影響せず、また逆に、実装クラスを追加しても機能のクラス階層に影響しない構造にすることができました。
Bridgeパターンのクラス図
1. Abstraction.java
public class Abstraction {
private Implementor impl;
public Abstraction(Implementor impl) {
this.impl = impl;
}
public void abstractionMethod() {
impl.implMethod();
}
}
2. RefinedAbstraction.java
public class RefinedAbstraction extends Abstraction { public RefinedAbstraction(Implementor impl) { super(impl); } public void refinedMethod() { System.out.println("追加機能"); } }
3. Implementor.java
public abstract class Implementor { public abstract void implMethod(); }
4. ConcreteImplementor.java
public class ConcreteImplementor extends Implementor { public void implMethod() { System.out.println("実装機能"); } }
5. Client.java
public class Client { public static void main(String[] args) { Abstraction abstraction = new Abstraction(new ConcreteImplementor()); RefinedAbstraction refinedAbstraction = new RefinedAbstraction(new ConcreteImplementor()); abstraction.abstractionMethod(); refinedAbstraction.abstractionMethod(); refinedAbstraction.refinedMethod(); } }
C:\sample\desin_pattern\bridge>javac Client.java [Enter] C:\sample\desin_pattern\bridge>java Client [Enter] 実装機能 実装機能 追加機能