Python ブリッジパターン
ブリッジパターンは構造型デザインパターンで、抽象部分と実装部分を分離し、それぞれを独立して変更できるようにします。簡単に言うと、つまり物事の複数の変化軸を分割し、各軸を独立して拡張できるようにすることです。。
身近なブリッジパターンの例え
リモコンとテレビの関係を想像してみてください:
- リモコン(抽象部分):制御インターフェースを提供する(電源、音量、チャンネル)
- テレビ(実装部分):具体的に操作を実行する(ソニーテレビ、サムスンテレビ、Xiaomiテレビ)
リモコンは具体的にどのテレビかを知る必要はなく、テレビもどのリモコンかを知る必要はありません。両者は「橋」を介して接続されており、それぞれ独立してアップグレード・モデルチェンジできます。
なぜブリッジパターンが必要なのか?
従来方式の限界
異なる形状と色をサポートする図形描画システムを設計するとしましょう:
例
# 従来の実装 - クラス爆発の問題
class RedCircle:
def draw(self):
print("赤い円を描画")
class BlueCircle:
def draw(self):
print("青い円を描画")
class RedRectangle:
def draw(self):
print("赤い長方形を描画")
class BlueRectangle:
def draw(self):
print("青い長方形を描画")
# 色や形状を追加するたびに、新しいクラスを作成する必要がある
# 3色 × 3形状 = 9クラス!
class RedCircle:
def draw(self):
print("赤い円を描画")
class BlueCircle:
def draw(self):
print("青い円を描画")
class RedRectangle:
def draw(self):
print("赤い長方形を描画")
class BlueRectangle:
def draw(self):
print("青い長方形を描画")
# 色や形状を追加するたびに、新しいクラスを作成する必要がある
# 3色 × 3形状 = 9クラス!
ブリッジパターンの利点
例
# ブリッジパターンの実装
class Color:
"""色インターフェース - 実装部分"""
def apply_color(self):
pass
class Shape:
"""形状抽象 - 抽象部分"""
def __init__(self, color):
self.color = color # ブリッジの鍵!
def draw(self):
pass
# 必要なのは:3色 + 3形状 = 6クラス
# ではなく:3 × 3 = 9クラス
class Color:
"""色インターフェース - 実装部分"""
def apply_color(self):
pass
class Shape:
"""形状抽象 - 抽象部分"""
def __init__(self, color):
self.color = color # ブリッジの鍵!
def draw(self):
pass
# 必要なのは:3色 + 3形状 = 6クラス
# ではなく:3 × 3 = 9クラス
ブリッジパターンの核となる構造
完全な例を通してブリッジパターンの構成要素を理解しましょう:

4つの重要な役割
- 抽象部分(Abstraction):抽象インターフェースを定義し、実装部分への参照を保持する
- 具体抽象(RefinedAbstraction):抽象インターフェースを拡張する
- 実装部分(Implementor):実装インターフェースを定義する
- 具体実装(ConcreteImplementor):具体的にインターフェースを実装する
完全なコード例:図形描画システム
ステップ1:実装部分のインターフェースを定義する(色)
例
from abc import ABC, abstractmethod
class Color(ABC):
"""色インターフェース - 実装部分"""
@abstractmethod
def apply_color(self):
pass
class Red(Color):
"""具体実装 - 赤"""
def apply_color(self):
return "赤"
class Blue(Color):
"""具体実装 - 青"""
def apply_color(self):
return "青"
class Green(Color):
"""具体実装 - 緑"""
def apply_color(self):
return "緑"
class Color(ABC):
"""色インターフェース - 実装部分"""
@abstractmethod
def apply_color(self):
pass
class Red(Color):
"""具体実装 - 赤"""
def apply_color(self):
return "赤"
class Blue(Color):
"""具体実装 - 青"""
def apply_color(self):
return "青"
class Green(Color):
"""具体実装 - 緑"""
def apply_color(self):
return "緑"
ステップ2:抽象部分を定義する(形状)
例
class Shape(ABC):
"""形状抽象 - 抽象部分"""
def __init__(self, color: Color):
self.color = color # ブリッジの鍵:実装部分の参照を保持する
@abstractmethod
def draw(self):
pass
class Circle(Shape):
"""具体抽象 - 円"""
def draw(self):
color_name = self.color.apply_color()
print(f"{color_name}の円を描画")
class Rectangle(Shape):
"""具体抽象 - 長方形"""
def draw(self):
color_name = self.color.apply_color()
print(f"{color_name}の長方形を描画")
class Triangle(Shape):
"""具体抽象 - 三角形"""
def draw(self):
color_name = self.color.apply_color()
print(f"{color_name}の三角形を描画")
"""形状抽象 - 抽象部分"""
def __init__(self, color: Color):
self.color = color # ブリッジの鍵:実装部分の参照を保持する
@abstractmethod
def draw(self):
pass
class Circle(Shape):
"""具体抽象 - 円"""
def draw(self):
color_name = self.color.apply_color()
print(f"{color_name}の円を描画")
class Rectangle(Shape):
"""具体抽象 - 長方形"""
def draw(self):
color_name = self.color.apply_color()
print(f"{color_name}の長方形を描画")
class Triangle(Shape):
"""具体抽象 - 三角形"""
def draw(self):
color_name = self.color.apply_color()
print(f"{color_name}の三角形を描画")
ステップ3:ブリッジパターンを使用する
例
# クライアントコード
def main():
# 色の実装を作成
red = Red()
blue = Blue()
green = Green()
# 形状抽象を作成し、色の実装をブリッジする
red_circle = Circle(red)
blue_rectangle = Rectangle(blue)
green_triangle = Triangle(green)
# 図形を描画
print("=== 図形描画結果 ===")
red_circle.draw() # 出力:赤い円を描画
blue_rectangle.draw() # 出力:青い長方形を描画
green_triangle.draw() # 出力:緑の三角形を描画
# 柔軟な組み合わせ:赤い長方形
red_rectangle = Rectangle(red)
red_rectangle.draw() # 出力:赤い長方形を描画
if __name__ == "__main__":
main()
def main():
# 色の実装を作成
red = Red()
blue = Blue()
green = Green()
# 形状抽象を作成し、色の実装をブリッジする
red_circle = Circle(red)
blue_rectangle = Rectangle(blue)
green_triangle = Triangle(green)
# 図形を描画
print("=== 図形描画結果 ===")
red_circle.draw() # 出力:赤い円を描画
blue_rectangle.draw() # 出力:青い長方形を描画
green_triangle.draw() # 出力:緑の三角形を描画
# 柔軟な組み合わせ:赤い長方形
red_rectangle = Rectangle(red)
red_rectangle.draw() # 出力:赤い長方形を描画
if __name__ == "__main__":
main()
実際の適用シーン
シーン1:メッセージ送信システム
例
from abc import ABC, abstractmethod
# 実装部分:メッセージ送信方法
class MessageSender(ABC):
@abstractmethod
def send(self, message):
pass
class EmailSender(MessageSender):
def send(self, message):
return f"メールで送信:{message}"
class SMSSender(MessageSender):
def send(self, message):
return f"SMSで送信:{message}"
class WeChatSender(MessageSender):
def send(self, message):
return f"WeChatで送信:{message}"
# 抽象部分:メッセージタイプ
class Message(ABC):
def __init__(self, sender: MessageSender):
self.sender = sender
@abstractmethod
def send(self):
pass
class UrgentMessage(Message):
def send(self):
message = "[緊急] " + self.get_content()
return self.sender.send(message)
def get_content(self):
return "システムに異常が発生しました。至急対応してください!"
class NormalMessage(Message):
def __init__(self, sender: MessageSender, content):
super().__init__(sender)
self.content = content
def send(self):
return self.sender.send(self.content)
# 使用例
def message_example():
email_sender = EmailSender()
sms_sender = SMSSender()
# 緊急メッセージをSMSで送信
urgent_sms = UrgentMessage(sms_sender)
print(urgent_sms.send()) # SMSで送信:[緊急] システムに異常が発生しました。至急対応してください!
# 通常メッセージをメールで送信
normal_email = NormalMessage(email_sender, "月次レポートが生成されました")
print(normal_email.send()) # メールで送信:月次レポートが生成されました
message_example()
# 実装部分:メッセージ送信方法
class MessageSender(ABC):
@abstractmethod
def send(self, message):
pass
class EmailSender(MessageSender):
def send(self, message):
return f"メールで送信:{message}"
class SMSSender(MessageSender):
def send(self, message):
return f"SMSで送信:{message}"
class WeChatSender(MessageSender):
def send(self, message):
return f"WeChatで送信:{message}"
# 抽象部分:メッセージタイプ
class Message(ABC):
def __init__(self, sender: MessageSender):
self.sender = sender
@abstractmethod
def send(self):
pass
class UrgentMessage(Message):
def send(self):
message = "[緊急] " + self.get_content()
return self.sender.send(message)
def get_content(self):
return "システムに異常が発生しました。至急対応してください!"
class NormalMessage(Message):
def __init__(self, sender: MessageSender, content):
super().__init__(sender)
self.content = content
def send(self):
return self.sender.send(self.content)
# 使用例
def message_example():
email_sender = EmailSender()
sms_sender = SMSSender()
# 緊急メッセージをSMSで送信
urgent_sms = UrgentMessage(sms_sender)
print(urgent_sms.send()) # SMSで送信:[緊急] システムに異常が発生しました。至急対応してください!
# 通常メッセージをメールで送信
normal_email = NormalMessage(email_sender, "月次レポートが生成されました")
print(normal_email.send()) # メールで送信:月次レポートが生成されました
message_example()
シーン2:デバイスリモコンシステム
例
# 実装部分:デバイス
class Device(ABC):
@abstractmethod
def turn_on(self):
pass
@abstractmethod
def turn_off(self):
pass
@abstractmethod
def set_volume(self, volume):
pass
class TV(Device):
def turn_on(self):
return "テレビがオンになりました"
def turn_off(self):
return "テレビがオフになりました"
def set_volume(self, volume):
return f"テレビの音量が設定されました:{volume}"
class Radio(Device):
def turn_on(self):
return "ラジオがオンになりました"
def turn_off(self):
return "ラジオがオフになりました"
def set_volume(self, volume):
return f"ラジオの音量が設定されました:{volume}"
# 抽象部分:リモコン
class RemoteControl:
def __init__(self, device: Device):
self.device = device
def toggle_power(self):
return "電源状態を切り替える"
def volume_up(self):
return "音量を上げる"
def volume_down(self):
return "音量を下げる"
class AdvancedRemoteControl(RemoteControl):
def mute(self):
return "ミュートモード"
def set_channel(self, channel):
return f"チャンネルを切り替える:{channel}"
# 使用例
def remote_example():
tv = TV()
radio = Radio()
basic_remote = RemoteControl(tv)
advanced_remote = AdvancedRemoteControl(radio)
print(basic_remote.toggle_power()) # 電源状態を切り替える
print(advanced_remote.mute()) # ミュートモード
remote_example()
class Device(ABC):
@abstractmethod
def turn_on(self):
pass
@abstractmethod
def turn_off(self):
pass
@abstractmethod
def set_volume(self, volume):
pass
class TV(Device):
def turn_on(self):
return "テレビがオンになりました"
def turn_off(self):
return "テレビがオフになりました"
def set_volume(self, volume):
return f"テレビの音量が設定されました:{volume}"
class Radio(Device):
def turn_on(self):
return "ラジオがオンになりました"
def turn_off(self):
return "ラジオがオフになりました"
def set_volume(self, volume):
return f"ラジオの音量が設定されました:{volume}"
# 抽象部分:リモコン
class RemoteControl:
def __init__(self, device: Device):
self.device = device
def toggle_power(self):
return "電源状態を切り替える"
def volume_up(self):
return "音量を上げる"
def volume_down(self):
return "音量を下げる"
class AdvancedRemoteControl(RemoteControl):
def mute(self):
return "ミュートモード"
def set_channel(self, channel):
return f"チャンネルを切り替える:{channel}"
# 使用例
def remote_example():
tv = TV()
radio = Radio()
basic_remote = RemoteControl(tv)
advanced_remote = AdvancedRemoteControl(radio)
print(basic_remote.toggle_power()) # 電源状態を切り替える
print(advanced_remote.mute()) # ミュートモード
remote_example()
ブリッジパターンの利点の比較
| 特性 | 従来方式 | ブリッジパターン |
|---|---|---|
| 拡張性 | 悪い、既存コードの修正が必要 | 良い、独立して拡張可能 |
| クラス数 | 多い、クラス爆発が起こりやすい | 少ない、線形に増加 |
| 保守性 | 困難、一箇所変更すると全体に影響 | 容易、責任の分離 |
| 柔軟性 | 固定の組み合わせ | 実行時の動的組み合わせ |
ベストプラクティスと注意点
使用するタイミング
✅ ブリッジパターンの使用に適した状況:
- 複数の軸で独立して拡張する必要がある場合
- 実行時に実装を切り替える必要がある場合
- 抽象と実装を恒久的にバインドすることを避ける場合
- 継承によってクラス階層が複雑になりすぎる場合
❌ 適さない状況:
- 変化の軸が少なく、複雑な設計が不要な場合
- 抽象と実装の間に強い結合関係がある場合
よくある間違いと回避方法
例
# 誤った例:本当に分離できていない
class BadShape:
def __init__(self, color_type):
if color_type == "red":
self.color = Red()
elif color_type == "blue":
self.color = Blue()
# 新しい色を追加するには、まだこのクラスを修正する必要がある
# 正しい方法:依存性注入
class GoodShape:
def __init__(self, color: Color): # 具体的な実装ではなく、インターフェースに依存する
self.color = color
class BadShape:
def __init__(self, color_type):
if color_type == "red":
self.color = Red()
elif color_type == "blue":
self.color = Blue()
# 新しい色を追加するには、まだこのクラスを修正する必要がある
# 正しい方法:依存性注入
class GoodShape:
def __init__(self, color: Color): # 具体的な実装ではなく、インターフェースに依存する
self.color = color
練習問題
練習1:図形システムの拡張
図形システムに以下の機能を追加してください:
- 新しい色(黄色)を追加
- 新しい形状(楕円形)を追加
- 黄色の楕円形を作成して描画する
練習2:決済システムの設計
決済システムを設計してください。要件:
- 支払い方法:Alipay、WeChat Pay、銀行カード
- 支払いタイプ:通常支払い、分割支払い、組み合わせ支払い
- ブリッジパターンを使用して、支払い方法と支払いタイプを独立して拡張できるようにします。
まとめ
ブリッジパターンは抽象と実装を分離することで、非常に高い柔軟性を提供します。その中核となる考え方は次のとおりです。
- 変化の次元を特定する:システム内で独立して変化し得る複数の次元を見つけ出す
- 橋を架ける:組み合わせ関係を通じて異なる次元を接続する
- 独立して拡張する:各次元は独立して発展・変化できる