gof-bridge について
抽象と実装を独立して変更するシステムの設計者向けに、GoF の Bridge パターンを解説するスキルです。コンポジション、実装の実行時切り替え、Adapter や Strategy との違いを扱います。
主な機能
- 01抽象と実装の分離
- 02並行するクラス階層の利用
- 03実行時の実装切り替え
- 04Bridge と Adapter の比較
- 05判断基準と注意点
活用シーン
- 01複数の形状とレンダラーへの対応
- 02抽象と実装の独立した進化
- 03プラットフォームや設定によるレンダラー選択
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill gof-bridgeインストール後、Claude Code で/gof-bridgeを入力して読み込まれたか確認します。
詳細
1 行での概要
抽象とその実装を切り離し、互いに独立して変更できるようにします。組み合わせによるサブクラスの爆発を、直交する 2 つの軸に沿ったコンポジションに置き換えます。
このスキルを使う場面
- 直交する 2 つの変化軸がある場合:N 種類の形状 × M 種類のレンダラー、または N 種類の描画ツール × M 種類のレンダリングバックエンド。Bridge を使わないと、N×M のサブクラスが必要になります。
- 抽象(例:
Shape)と実装(例:Renderer)の両方が、場合によっては異なるチームによって保守されながら、時間とともに独立して進化していくと見込まれる場合。 - 実行時に実装を切り替えたい場合。プラットフォーム、環境、設定ごとに別のレンダラーを選べます。
このスキルを使わない場面
- 2 つの軸のうち、実際に変化するのが一方だけの場合。もう一方には実装が 1 つしかなく、別の実装も見込まれません。Bridge は過剰な設計です。
- 「2 つの軸」が実際には直交しておらず、互いに連動して結合を強いる場合。Bridge の価値は独立性に依存します。
- 既存の互換性のない 2 つのインターフェースを後付けで連携させる場合。それは Bridge ではなく
gof-adapterです。Bridge はあらかじめ設計するものです。
主な内容
2 つの並行する階層:
- 抽象 — クライアント向けの概念(
Shape、RemoteControl、Notification)。Implementor への参照を保持します。 - Implementor — 基盤となるインターフェース(
Renderer、Device、DeliveryChannel)。具象 Implementor は実行時に組み込まれます。
抽象は保持している Implementor に具体的な処理を委譲します。2 つの階層は独立して拡張できます。新しい Shape を追加しても新しい Renderer サブクラスは不要で、その逆も同様です。
abstract class Shape(val renderer: Renderer) {
abstract fun draw()
}
interface Renderer { fun renderCircle(x, y, r); fun renderSquare(x, y, s) }
class Circle(renderer: Renderer, val x, y, r): Shape(renderer) {
override fun draw() = renderer.renderCircle(x, y, r)
}
class VectorRenderer: Renderer { ... }
class RasterRenderer: Renderer { ... }
新しい Shape(Triangle)を追加するには、任意の Renderer で描画する方法を定義します。新しい Renderer(SVGRenderer)を追加すれば、既存のすべての Shape がそのまま SVG で動作します。
Bridge と Adapter の違い。 コンポジションの構造は同じですが、意図と導入時期が異なります:
- Adapter は互換性のないインターフェースを後付けで連携させます。多くの場合、システムの境界で適用されます。
- Bridge は抽象と実装を切り離すために意図的に選択する設計で、両者が変化できるよう、あらかじめ設計します。
判断の目安
- 両方の軸に 2 種類以上のバリエーションがあり、さらに増えると見込まれる場合、Bridge の効果が得られます。
- 実装だけが変化し、抽象が固定されている場合、それは Bridge ではなく
gof-strategyです。 - Implementor はコンストラクター(または DI)で注入し、抽象を変更せずに差し替えられるようにします。
アンチパターン
- 実際には一方しか変化しないのに Bridge を導入すること。サブクラスが 1 つだけの抽象クラスと、実装が 1 つだけのインターフェースでは、無用な形式にすぎません。
- Implementor が抽象の API に漏れ出す Bridge。分離の目的が損なわれます。
- 抽象のコンストラクター内で
Implementorの選択をハードコードすること。Bridge で解消するはずだった結合が残ります。
関連項目
gof-adapter— 同じコンポジション構造を使い、既存の互換性のないインターフェースを後付けで連携させます。gof-strategy— 変化する軸が実装の 1 つだけの Bridge です。gof-kotlin-idioms— Kotlin の Bridge は多くの場合、インターフェースをパラメーターに取るコンポジションだけで実現でき、抽象クラスは不要です。
参考資料
- Design Patterns(GoF、1994 年)、第 4 章 — Bridge。(HFDP 第 2 版には含まれていません。)
- Kotlin Design Patterns and Best Practices(Alexey Soshin)、第 3 章 — Bridge。
コメント
Markdown 対応