Featured image of post Bridgeパターンの設計を振り返る - Perl GoFパターン実践まとめ【第7回】

Bridgeパターンの設計を振り返る - Perl GoFパターン実践まとめ【第7回】

Bridgeパターンの設計を総括し、AdapterやStrategyとの違いを明確化。Perlによる GoF パターン実装のベストプラクティスと、実務での応用例をまとめます。

PerlとMooで「ランダムダンジョンジェネレーター」を作る連載の最終回です。

今回は、これまでの設計を振り返り、Bridgeパターンの本質と他のパターンとの違いを整理します。

シリーズ完成おめでとう

完成したシステムの全体像

7回の連載を通じて、以下のシステムを構築しました。

	classDiagram
    class DungeonTheme {
        <<abstract>>
        +algorithm: GenerationAlgorithm
        +width: Int
        +height: Int
        +map: Array
        +generate()
        +render()
        +wall_char()*
        +floor_char()*
    }

    class CaveTheme {
        +wall_char() "#"
        +floor_char() "."
    }

    class CastleTheme {
        +wall_char() "█"
        +floor_char() "░"
    }

    class RuinsTheme {
        +wall_char() "▓"
        +floor_char() "▒"
    }

    class UnderwaterTempleTheme {
        +wall_char() "≈"
        +floor_char() "~"
    }

    class GenerationAlgorithm {
        <<role>>
        +generate(map, width, height)*
    }

    class RandomAlgorithm {
        +generate(map, width, height)
    }

    class MazeAlgorithm {
        +visited: Hash
        +generate(map, width, height)
        -_carve(map, width, height, x, y)
    }

    class BSPAlgorithm {
        +min_size: Int
        +regions: Array
        +rooms: Array
        +generate(map, width, height)
        -_split_region(x, y, w, h)
        -_create_room(map, x, y, w, h)
        -_connect_rooms(map)
    }

    DungeonTheme <|-- CaveTheme
    DungeonTheme <|-- CastleTheme
    DungeonTheme <|-- RuinsTheme
    DungeonTheme <|-- UnderwaterTempleTheme
    DungeonTheme o-- GenerationAlgorithm : 委譲
    GenerationAlgorithm <|.. RandomAlgorithm
    GenerationAlgorithm <|.. MazeAlgorithm
    GenerationAlgorithm <|.. BSPAlgorithm

Bridgeパターンの構成要素

GoFの定義に従って、今回のシステムを整理します。

GoFの用語今回の実装役割
AbstractionDungeonTheme抽象側の基底クラス
RefinedAbstractionCave/Castle/Ruins/UnderwaterTempleTheme抽象側の具象クラス
ImplementorGenerationAlgorithm(Role)実装側のインターフェース
ConcreteImplementorRandom/Maze/BSPAlgorithm実装側の具象クラス

Bridgeパターンが解決する問題

Bridgeパターンは、以下の問題を解決します。

  1. クラス爆発の回避

n種類の抽象 × m種類の実装 = n×m クラス が必要な状況を、n+m クラスで済むようにします。

  1. 独立した拡張

抽象(テーマ)と実装(アルゴリズム)を独立に拡張できます。 新しいテーマを追加しても、既存のアルゴリズムには影響しません。 逆も同様です。

  1. 実行時の組み合わせ

継承では静的に決まる組み合わせを、委譲により実行時に動的に決定できます。

他のパターンとの比較

Bridgeパターンと混同されやすいパターンとの違いを整理します。

Adapterパターンとの違い

観点BridgeAdapter
目的抽象と実装を分離インターフェースを変換
設計時期システム設計時既存システムの統合時
構造両側を自ら設計一方は既存

Adapterは「後から」既存のクラスを別のインターフェースに適合させます。 Bridgeは「最初から」拡張性を考慮して設計します。

Strategyパターンとの違い

観点BridgeStrategy
対象複数の変動軸1つのアルゴリズム軸
Abstraction側階層を持つ1つのContextのみ
連携抽象と実装が協調アルゴリズムのみ交換

Strategyは1つの軸(アルゴリズム)だけを切り替えます。 Bridgeは2つの軸(抽象と実装)を独立に変化させます。

今回のダンジョンジェネレーターでは、もしテーマが1種類だけで、アルゴリズムだけを切り替えたいなら、Strategyパターンで十分です。

Bridgeパターンを使うべき場面

以下の条件が揃ったときに、Bridgeパターンを検討しましょう。

  • 2つの独立した変動軸がある
  • それぞれの軸で拡張が見込まれる
  • 組み合わせ爆発を避けたい

例えば以下のような場面です。

  • 複数のOS × 複数のGUIフレームワーク
  • 複数のデータベース × 複数のORM
  • 複数の通知チャネル × 複数のメッセージ形式

実務での応用例

今回のダンジョンジェネレーターは楽しい題材でしたが、実務でもBridgeパターンは活用できます。

レポート生成システム

  • Abstraction: レポート形式(PDF、HTML、Excel)
  • Implementor: データソース(DB、API、ファイル)

通知システム

  • Abstraction: メッセージ形式(緊急、定期、リマインダー)
  • Implementor: 配信チャネル(Slack、Email、SMS)

描画システム

  • Abstraction: 図形(円、四角、三角)
  • Implementor: 描画API(OpenGL、DirectX、SVG)

連載を通じて学んだこと

この連載では、以下のことを学びました。

  • 二次元配列とASCII artでダンジョンを表現
  • 複数のアルゴリズム(ランダム、迷路、BSP)
  • クラス爆発問題とそのアンチパターン
  • Bridgeパターンによる抽象と実装の分離
  • Moo Roleを使ったインターフェース定義
  • Open/Closed原則の実践

最初はシンプルなダンジョン生成から始まり、問題に直面し、パターンで解決するという体験を通じて、Bridgeパターンの本質を理解できたのではないでしょうか。

ファイル一覧

最終的なファイル構成は以下の通りです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.
├── DungeonTheme.pm          # 抽象の基底クラス
├── CaveTheme.pm             # 洞窟テーマ
├── CastleTheme.pm           # 城テーマ
├── RuinsTheme.pm            # 遺跡テーマ
├── UnderwaterTempleTheme.pm # 水中神殿テーマ
├── GenerationAlgorithm.pm   # アルゴリズムのRole
├── RandomAlgorithm.pm       # ランダム配置
├── MazeAlgorithm.pm         # 迷路型
└── BSPAlgorithm.pm          # 部屋区分型

9モジュールで、12通り(4テーマ×3アルゴリズム)の組み合わせを実現しています。

今回のまとめ

最終回では、Bridgeパターンの設計を振り返りました。

  • Bridgeパターンは抽象と実装を分離する
  • n×m クラスが n+m クラスに削減
  • AdapterやStrategyとは目的が異なる
  • 2つの独立した変動軸があるときに有効

この連載で作成したダンジョンジェネレーターは、「友人に自慢できる」成果物です。 ぜひ新しいテーマやアルゴリズムを追加して、自分だけのダンジョンを作ってみてください。

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。