2012-01-25 21 views
4

說,我有兩個作用:簡單::稅和房地產稅::。在測試情況下,我想使用Simple :: Tax,而在生產中,我想使用Real :: Tax。做這個的最好方式是什麼?我首先想到的是使用不同版本的new方法來創建具有不同角色的對象:如何在穆斯處理嘲笑角色?

#!/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聲明:

#!/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"; 

是這些比其他的更好的,是有什麼可怕的關於任何一方的,並且是有沒有更好的辦法,我還沒想過呢。

回答

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你可以做幾件事情要重寫複雜::稅的實施。

例如,你可以只定義簡單::稅,像這樣:

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

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

然後總是有一個撰寫Complex::Tax和(使用apply_all_roles)僅在試驗適用簡易::稅吧。

然而,如果你需要簡單::稅及複合稅::無論在生產(而不是簡單地進行測試)最好的辦法是從組合關係(做)的授權關係。(有)重構。

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

所以,'各地calculate_tax'方法在簡單稅制的作用從來沒有實際調用對象的'calculate_tax'方法,對嗎?我認爲這是最乾淨的方式。 –

+0

的確,您完全重寫了使用'around'替換它的父方法。 – perigrin