2012-01-25 6 views
4

シンプル::税とリアル::税の2つの役割があるとします。テスト環境では、Simple :: Taxを使いたいのですが、実務ではReal :: Taxを使いたいと思います。これを行う最善の方法は何ですか?私が最初に考えたのは異なる役割を持つオブジェクトを作成するために、new方法の異なるバージョンを使用していた:Mooseでモーキングの役割を処理する方法は?

#!/usr/bin/perl 

use warnings; 

{ 
    package Simple::Tax; 
    use Moose::Role; 

    requires 'price'; 

    sub calculate_tax { 
     my $self = shift; 
     return int($self->price * 0.05); 
    } 
} 


{ 
    package A; 
    use Moose; 
    use Moose::Util qw(apply_all_roles); 

    has price => (is => "rw", isa => 'Int'); #price in pennies 

    sub new_with_simple_tax { 
     my $class = shift; 
     my $obj = $class->new(@_); 
     apply_all_roles($obj, "Simple::Tax"); 
    } 
} 

my $o = A->new_with_simple_tax(price => 100); 
print $o->calculate_tax, " cents\n"; 

私の第二の考えは異なるwithステートメントを使用するためのパッケージの本体でif文を使用していた:

#!/usr/bin/perl 

use warnings; 

{ 
    package Complex::Tax; 
    use Moose::Role; 

    requires 'price'; 

    sub calculate_tax { 
     my $self = shift; 
     #pretend this is more complex 
     return int($self->price * 0.15); 
    } 
} 

{ 
    package Simple::Tax; 
    use Moose::Role; 

    requires 'price'; 

    sub calculate_tax { 
     my $self = shift; 
     return int($self->price * 0.05); 
    } 
} 


{ 
    package A; 
    use Moose; 

    has price => (is => "rw", isa => 'Int'); #price in pennies 

    if ($ENV{TEST_A}) { 
     with "Simple::Tax"; 
    } else { 
     with "Complex::Tax"; 
    } 
} 

my $o = A->new(price => 100); 
print $o->calculate_tax, " cents\n"; 

これらのうちの1つは他のものより優れていますか、どちらかについて恐ろしいものがありますか、まだ私が考えていないより良い方法があります。

答えて

5

私の最初の提案はMooseX::Traitsようなものにし、オブジェクトの作成時に異なる役割を指定します:

my $test = A->with_traits('Simple::Tax')->new(...); 

my $prod = A->with_traits('Complex::Tax')->new(...); 

しかし、これはいずれか役割が適用されずに作成されてAへの扉を開きます。それをさらに考えてみると、X/Y問題があると思います。 Simple::Taxがテスト環境でComplex::Taxをモックアップするために使用された場合は、Complex :: Tax実装をオーバーライドするためにいくつかのことができます。

package Simple::Tax; 
use Moose::Role; 

requires 'calculate_tax'; 
around calculate_tax => sub { int($_[1]->price * 0.05) }; 

は、常にコン Complex::Taxを持っており、( apply_all_rolesを使用して)のみのテストの間にそれにシンプル::税を適用します。

たとえば、あなたはちょうどそうのような単純な::税を定義することができます。

ただし、シンプルなもの::: TaxとComplex :: Taxが必要です(テスト用ではありません)。最高のベットは、リレーションシップ関係から委譲関係(has)へのリファクタリングです。

package TaxCalculator::API; 
use Moose::Role; 

requires qw(calculate_tax); 

package SimpleTax::Calculator; 
use Moose; 
with qw(TaxCalculator::API); 

sub calculate_tax { ... } 

package ComplexTax::Calculator; 
use Moose; 
with qw(TaxCalculator::API); 

sub calcuate_tax { ... } 


package A; 
use Moose; 

has tax_calculator => ( 
     does => 'TaxCalculator::API', 
     handles => 'TaxCalculator::API', 
     default => sub { ComplexTax::Calculator->new() }, 
); 

あなたはそれを上書きしたい場合、あなたは、単に新しいtax_calculatorに渡す:

my $test = A->new(tax_calculator => SimpleTax::Calculator->new()); 

my $prod = A->new(tax_calculator => ComplexTax::Calculator->new()); 

handlesが、これは構成したことに実質的に同一の新しいプロキシとしての役割から、すべてのメソッドを委譲しますのであなた自身の役割。

+0

したがって、単純な税の役割の 'around calculate_tax'メソッドは、実際にオブジェクトの' calculate_tax'メソッドを呼び出すことはありません。私はそれが一番クリーンな方法だと思う。 –

+0

正確には、あなたはそれを置き換えるために 'around'を使って親メソッドを完全にオーバーライドします。 – perigrin

関連する問題