デザインパターン学習メモ:「Bridge」


このパターンの目的

GoF本より引用する。

抽出されたクラスと実装を分離して、それらを独立に変更できるする。(P.163)

流動的な要素が複数あるときに、それらを別の階層として扱う。(二つの階層の接続はコンポジションを用いる)
そうすることで、それぞれ独立して変更することができ、将来的なクラス数の増大に備えることができる。

実装例

『オブジェク指向のこころ』(P.163)を参考に作成

「抽出されたクラス」の階層

Shape.java
// Abstractionの役割
public abstract class Shape {
    protected Drawing drawing;  // 実装を表すクラスのインスタンス

    public Shape(Drawing drawing) {
        this.drawing = drawing;
    }

    abstract void draw();

    protected void drawingLine(double x1, double y1, double x2, double y2) {
        drawing.drawLine(x1, y1, x2, y2);
    }

    void drawCircle(double x, double y, double r) {
        drawing.drawCircle(x, y, r);
    }
}
Rectangle.java
// RefinedAbstraction の役割
public class Rectangle extends Shape {
    private double x1, x2, y1, y2;

    public Rectangle(Drawing drawing, double x1, double x2, double y1, double y2) {
        super(drawing);
        this.x1 = x1;
        this.x2 = x2;
        this.y1 = y1;
        this.y2 = y2;
    }

    @Override
    void draw() {
        drawing.drawLine(x1, y1, x2, y1);
        drawing.drawLine(x2, y1, x2, y2);
        drawing.drawLine(x2, y2, x1, y2);
        drawing.drawLine(x1, y2, x1, y1);
    }
}
Circle.java
// Abstractionの役割
public class Circle extends Shape {
    private double x, y, r;

    public Circle(Drawing drawing, double x, double y, double r) {
        super(drawing);
        this.x = x;
        this.y = y;
        this.r = r;
    }

    @Override
    void draw() {
        drawing.drawCircle(x, y, r);
    }
}

「実装」の階層

Drawing.java
// Implementorの役割
public interface Drawing {
    void drawLine(double x1, double y1, double x2, double y2);
    void drawCircle(double x, double y, double r);
}
FooSystemDrawing.java
// Concrete Implementorの役割
public class FooSystemDrawing implements Drawing {

    @Override
    public void drawLine(double x1, double y1, double x2, double y2) {
        // FooSystemに依存した線分の描画処理
    }

    @Override
    public void drawCircle(double x, double y, double r) {
        // FooSystemに依存した円の描画処理
    }
}
BarSystemDrawing.java
// Concrete Implementorの役割
public class BarSystemDrawing implements Drawing{

    @Override
    public void drawLine(double x1, double y1, double x2, double y2) {
        // BarSystemに依存した線分の描画処理
    }

    @Override
    public void drawCircle(double x, double y, double r) {
        // BarSystemに依存した円の描画処理
    }
}

実装例の解説

Shapeクラスが抽出されたクラスである。クライアントは図形をShapeクラスとして扱う。(ポリモーフィズム)

この図形の描画方法は、各システム(Fooシステム、Barシステム)によって異なるので、その描画方法は「実装の階層」として分離する。
こうすることで、今後bazシステムに対応する必要があったときに、BarSystemDrawingクラスを作ることだけで対応可能になる。

各書籍における表現の違い

参考にした書籍で、Bridgeパターンの表現がそれぞれ異なっていて面白かったので紹介する。

GoF本の原書

Decouple an abstraction from its implementation

GoF本の翻訳

抽出されたクラスと実装を分離

「抽出」は、「オブジェクト指向分析の結果、クラスとして抽出された」という意味だろうか

『Java言語で学ぶ デザインパターン入門』

「機能のクラス階層」と「実装のクラス階層」

「クラス階層」という表現はわかりやすい。「機能」という表現がやや気になる。(あまりピンとこない)

『オブジェクト指向のこころ』

抽象的側面と実装

翻訳を読んでいるので、原書がどうなっているのか分からない。
「抽象的側面」はGoF本と同じく"abstraction"となっているのか、違うのか。(違う気がする)

『アジャイルソフトウェア開発の奥義』

抽象的な部分と具体的な部分に分離

参考文献

  • エリック ガンマ、ラルフ ジョンソン、リチャード ヘルム、ジョン プリシディース(1999)『オブジェクト指向における再利用のためのデザインパターン 改訂版』本位田 真一、吉田 和樹 監訳、SBクリエイティブ
  • ロバート・C・マーチン(2004)『アジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技』瀬谷啓介訳、SBクリエイティブ
  • アラン・シャロウェイ、ジェームズ・R・トロット(2014)『デザインパターンととともに学ぶ オブジェクト指向のこころ』村上雅章訳、丸善出版
  • 結城浩(2004)『Java言語で学ぶ デザインパターン入門』SBクリエイティブ