Bridgeパターン
実装のクラス階層と機能のクラス階層を分離し、委譲を使って両者を橋渡し(Bridge)する。
- 機能と実装がごっちゃになってきたら、Bridgeパターンを使うタイミング。
- プラットフォームやフォーマットの違いを実装側に隠蔽し、機能側では抽象メソッドを用意する。
メリット
- 実装クラスを追加するのが容易、かつ見通しがよい
- 利用側から実装の詳細を隠蔽し、抽象化できる
- 利用側が実行時に動的に実装クラスを決めることができる
やってみる
平均値の計算を異なる実装でつくってみた(実にアホらしいが)
※実装の詳細を隠蔽する必要があるケースでやってみればよかったなぁ
- Implementer
package Static; sub new { my ($class, @data) = @_; return bless \@data, $class; } sub mean { } 1;
- ConcreteImplementer
package Static::Pure; use base qw(Static); sub mean { my ($self) = @_; my $sum = 0; for my $data (@$self) { $sum += $data; } return scalar @$self ? $sum / scalar @$self: 0; } 1;
- ConcreteImplementer
package Static::Cpan; use base qw(Static); use Statistics::Descriptive; sub mean { my ($self) = @_; my $stat = Statistics::Descriptive::Sparse->new(); $stat->add_data(@$self); return $stat->mean(); } 1;
- Abstraction
package PrintStat; use Static; use Static::Pure; use Static::Cpan; sub new { my ($class, $impl) = @_; return bless { component => $impl }, $class; } sub print_mean { my $self = shift; my $stat = $self->{component}; print $stat->mean(), "\n"; } 1;
- Main
use Static::Pure; use Static::Cpan; use PrintStat; my @data = qw(1 2 3 4 5); my $p_stat1 = new PrintStat(new Static::Pure(@data)); $p_stat1->print_mean(); my $p_stat2 = new PrintStat(new Static::Cpan(@data)); $p_stat2->print_mean();
まとめ
- Bridgeパターンは実装の詳細を隠蔽し、機能の抽象度を高めることができる
- Adapterパターンと似ているが、Adapterパターンは既存クラスを再利用して異なるインタフェースを持たせるためのもの、Bridgeパターンは実装と機能を明確に分離し、実装クラスと機能を橋渡しするものである。