![Bridge](/images/patterns/cards/bridge-mini.png?id=b389101d8ee8e23ffa1b534c704d0774)
Bridge を Ruby で
Bridge は、 構造に関するデザインパターンの一つで、 ビジネス・ロジックや巨大なクラスを独立して開発可能なクラス階層に分割します。
階層の一つ (抽象化と呼ばれる) は、 二つ目の階層 (実装) のオブジェクトへの参照を持ちます。 抽象化階層は、 その呼び出しのいくつか (場合によっては大多数) を実装階層のオブジェクトに委任します。 すべての実装は、 共通のインターフェースを持っているので、 抽象化の中で入れ替え可能です。
複雑度:
人気度:
使用例: Bridge パターンは、 クロス・プラットフォーム・アプリを扱う時、 複数の種類のデータベース・サーバーをサポートする時、 あるいはある種の API プロバイダー (クラウド・プラットフォーム、 ソーシャル・ネットワークなど) を複数利用したい場合に特に便利です。
見つけ方: Bridge は、 制御するものと、 それが依存するいくつかの異なるプラットフォームとが明らかに分かれていることから識別できます。
概念的な例
この例は、 Bridge デザインパターンの構造を説明するためのものです。 以下の質問に答えることを目的としています:
- どういうクラスからできているか?
- それぞれのクラスの役割は?
- パターンの要素同士はどう関係しているのか?
main.rb: 概念的な例
# The Abstraction defines the interface for the "control" part of the two class
# hierarchies. It maintains a reference to an object of the Implementation
# hierarchy and delegates all of the real work to this object.
class Abstraction
# @param [Implementation] implementation
def initialize(implementation)
@implementation = implementation
end
# @return [String]
def operation
"Abstraction: Base operation with:\n"\
"#{@implementation.operation_implementation}"
end
end
# You can extend the Abstraction without changing the Implementation classes.
class ExtendedAbstraction < Abstraction
# @return [String]
def operation
"ExtendedAbstraction: Extended operation with:\n"\
"#{@implementation.operation_implementation}"
end
end
# The Implementation defines the interface for all implementation classes. It
# doesn't have to match the Abstraction's interface. In fact, the two interfaces
# can be entirely different. Typically the Implementation interface provides
# only primitive operations, while the Abstraction defines higher-level
# operations based on those primitives.
class Implementation
# @abstract
#
# @return [String]
def operation_implementation
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
end
# Each Concrete Implementation corresponds to a specific platform and implements
# the Implementation interface using that platform's API.
class ConcreteImplementationA < Implementation
# @return [String]
def operation_implementation
'ConcreteImplementationA: Here\'s the result on the platform A.'
end
end
class ConcreteImplementationB < Implementation
# @return [String]
def operation_implementation
'ConcreteImplementationB: Here\'s the result on the platform B.'
end
end
# Except for the initialization phase, where an Abstraction object gets linked
# with a specific Implementation object, the client code should only depend on
# the Abstraction class. This way the client code can support any abstraction-
# implementation combination.
def client_code(abstraction)
# ...
print abstraction.operation
# ...
end
# The client code should be able to work with any pre-configured abstraction-
# implementation combination.
implementation = ConcreteImplementationA.new
abstraction = Abstraction.new(implementation)
client_code(abstraction)
puts "\n\n"
implementation = ConcreteImplementationB.new
abstraction = ExtendedAbstraction.new(implementation)
client_code(abstraction)
output.txt: 実行結果
Abstraction: Base operation with:
ConcreteImplementationA: Here's the result on the platform A.
ExtendedAbstraction: Extended operation with:
ConcreteImplementationB: Here's the result on the platform B.