1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【デザインパターン】ブリッジパターン解説(Flutter / Android 実例付き)

Last updated at Posted at 2025-08-26

1. パターンの意図

ブリッジ(Bridge)パターン は、
抽象(Abstraction)と実装(Implementation)を分離して、それぞれ独立に拡張可能にする デザインパターンです。

解決する問題

  • クラスの 多重継承の爆発(組み合わせ爆発) を防ぎたい
  • UI テーマ × プラットフォーム のように、2軸で独立に拡張したい
  • 抽象(何をするか)と実装(どうやるか)を疎結合に保ちたい

ポイント

  • 「抽象(Abstraction)」と「実装(Implementation)」を別クラスに分ける
  • 両者は 委譲(delegation) でつながる
  • それぞれを独立に拡張できる

2. UML 図

  • Abstraction:上位の抽象(例:UIコンポーネント)
  • Implementor:下位の実装インターフェース(例:描画エンジン)
  • RefinedAbstraction:Abstraction の拡張
  • ConcreteImplementor:実装の具体化

3. Flutter / Dart 実装例

3.1 Implementor(実装)

abstract class Renderer {
  void render(String shape);
}

class VectorRenderer implements Renderer {
  @override
  void render(String shape) {
    print("Drawing $shape as lines");
  }
}

class RasterRenderer implements Renderer {
  @override
  void render(String shape) {
    print("Drawing $shape as pixels");
  }
}

3.2 Abstraction(抽象)

abstract class Shape {
  Renderer renderer;
  Shape(this.renderer);

  void draw();
}

class Circle extends Shape {
  Circle(Renderer renderer) : super(renderer);

  @override
  void draw() {
    renderer.render("Circle");
  }
}

3.3 利用例

void main() {
  var vectorCircle = Circle(VectorRenderer());
  vectorCircle.draw(); // Drawing Circle as lines

  var rasterCircle = Circle(RasterRenderer());
  rasterCircle.draw(); // Drawing Circle as pixels
}

4. Android / Kotlin 実装例

4.1 Implementor

interface Renderer {
    fun render(shape: String)
}

class VectorRenderer : Renderer {
    override fun render(shape: String) {
        println("Drawing $shape as lines")
    }
}

class RasterRenderer : Renderer {
    override fun render(shape: String) {
        println("Drawing $shape as pixels")
    }
}

4.2 Abstraction

abstract class Shape(protected val renderer: Renderer) {
    abstract fun draw()
}

class Circle(renderer: Renderer) : Shape(renderer) {
    override fun draw() {
        renderer.render("Circle")
    }
}

4.3 利用例

fun main() {
    val vectorCircle = Circle(VectorRenderer())
    vectorCircle.draw() // Drawing Circle as lines

    val rasterCircle = Circle(RasterRenderer())
    rasterCircle.draw() // Drawing Circle as pixels
}

5. メリット / デメリット

メリット

  • 抽象と実装を独立して拡張できる
  • 組み合わせ爆発を回避できる
    • 例:Shape × Renderer = 2×2 = 4 通り → Bridge で分離すれば管理が楽
  • 保守性・テスト性が高い

デメリット

  • 設計が少し複雑になる
  • 小規模な場合はオーバーエンジニアリング

6. 実務ユースケース

Flutter

  • 描画系ライブラリ:Canvas / Skia / CustomPaint の切替
  • テーマ切替:Material / Cupertino の UI コンポーネント抽象化
  • データ永続化:Repository 抽象 × ストレージ実装(SQLite, SharedPreferences, Hive)

Android (Kotlin)

  • View 抽象 × Renderer 実装
  • Repository 抽象 × DataSource 実装(Local / Remote)
  • UI テーマと描画エンジンの分離

7. 実装上の注意点

Flutter / Dart

  • **依存性注入(DI)**と組み合わせると効果的
  • Shape(抽象)をテストする際に Renderer をモック化可能

Android / Kotlin

  • Repository パターンと一緒に使われることが多い
  • Bridge と Adapter の違いに注意
    • Adapter:インターフェース不一致を変換
    • Bridge:抽象と実装を分離して並行拡張

8. どんなときに使う?

  • 「抽象 × 実装」が組み合わせ爆発しそうなとき
  • 両者を独立に進化させたいとき
  • プラットフォーム依存部分を切り離したいとき

まとめ

  • ブリッジパターンは「抽象と実装を分離」して拡張性を高めるパターン
  • Flutter では Renderer と Shape の分離、Android では Repository と DataSource の分離に多用
  • Adapter が “既存の不一致解消” なのに対して、Bridge は “将来の拡張性確保” が目的

付記

組み合わせ爆発の例(Bridge 導入前)

例えば 図形(Shape) と 描画方式(Renderer) を両方サブクラスで表現すると:

  • Shape:Circle, Square

  • Renderer:Vector, Raster

これを素直に継承で組み合わせると…

👉 2 × 2 = 4 クラス
👉 もし「Triangle」を追加すれば、3 × 2 = 6クラス に増える。

このように Shape × Renderer の掛け算でクラス数が爆発します。

Bridge 導入後(抽象と実装を分離)

Bridge パターンを使って Shape と Renderer を分離すると:

👉 Shape = 2(Circle, Square)
👉 Renderer = 2(Vector, Raster)

  • Triangle を追加しても Triangle クラス1つ増えるだけ

  • Renderer 側(Vector / Raster)はそのまま再利用可能

  • クラス数は 「掛け算」ではなく「足し算」 で増える

👉 3 + 2 = 5 クラスクラス に増える。

図解イメージまとめ

  • Bridge 導入前
    • CircleVector / CircleRaster / SquareVector / SquareRaster … クラス爆発
  • Bridge 導入後
    • Shape と Renderer を分離し、委譲で組み合わせる
    • クラス数は 足し算 で済む
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?