Bridgeパターン

実装のクラス階層と機能のクラス階層を分離し、委譲を使って両者を橋渡し(Bridge)する。

  • 機能と実装がごっちゃになってきたら、Bridgeパターンを使うタイミング。
  • プラットフォームやフォーマットの違いを実装側に隠蔽し、機能側では抽象メソッドを用意する。
メリット
  1. 実装クラスを追加するのが容易、かつ見通しがよい
  2. 利用側から実装の詳細を隠蔽し、抽象化できる
  3. 利用側が実行時に動的に実装クラスを決めることができる
使用例
やってみる

平均値の計算を異なる実装でつくってみた(実にアホらしいが)
※実装の詳細を隠蔽する必要があるケースでやってみればよかったなぁ

  • 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パターンは実装と機能を明確に分離し、実装クラスと機能を橋渡しするものである。