はじめに
現在デザインパターンについて勉強中です。
今回はBridgeついてまとめました。
Bridge
Bridgeはクラスの余計な拡張を防ぐために橋渡しとなるクラスを使う、構造に関するデザインパターンの一つです。
例えば、Circle
クラスとSquare
クラスが存在するとき、描画方法に関する派生クラスVectorRenderer~
とRasterRenderer~
を考えると以下のようになります。
このとき、VectorRendererCircle
やVectorRendererSquare
は描画方法が共通なので似たような性質をもち、実質同じようなクラスが2つあることになります。
また、新しい派生クラスを追加しようとすると、~RendererCircle
と~RendererSquare
が新しく作られ、コードの重複がさらに増えていってしまいます。
このような問題を解決するために、Bridgeパターンを使います。
まずは親クラスShape
とRenderer
を用意し、それぞれから形状に関するクラスと描画方法に関するクラスを派生(継承)します。
- Shape - Square, Circle, Triangle, ...
- Renderer - Raster, Vector, ...
そして、Shape
から派生する継承関係は形状のみで、描画方法に関する情報はRenderer
クラスに委譲(Renderer
のインスタンスを生成してShape
のconstructorに渡す)します。
この構造によって、形状と描画方法はそれぞれ独立して拡張することができ、クラスの数も減らすことができるようになります。
実装例
以上の内容を実装したのがこちらです。
簡単のため、Shape
からCircle
クラスのみを派生させて検証しました。
class VectorRenderer
{
renderCircle(radius)
{
console.log(`Drawing a circle of radius ${radius}`);
}
}
class RasterRenderer
{
renderCircle(radius)
{
console.log(`Drawing pixels for circle of radius ${radius}`);
}
}
class Shape
{
constructor(renderer)
{
this.renderer = renderer;
}
}
class Circle extends Shape
{
constructor(renderer, radius) {
super(renderer);
this.radius = radius;
}
draw()
{
this.renderer.renderCircle(this.radius);
}
resize(factor)
{
this.radius *= factor;
}
}
描画方法に関するクラスのメソッドについては委譲で使用するため、以下のようにインスタンス(raster
, vector
)をつくってCircle
に引数として渡しています。
let raster = new RasterRenderer();
let vector = new VectorRenderer();
let circle = new Circle(vector, 5);
circle.draw();
circle.resize(2);
circle.draw();
結果以下のようになります。
Drawing a circle of radius 5
Drawing a circle of radius 10
参考資料