假设我有两个角色:Simple :: Tax和Real :: Tax.在测试情况下,我想使用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";
Run Code Online (Sandbox Code Playgroud)
我的第二个想法是在包的主体中使用if语句来使用不同的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";
Run Code Online (Sandbox Code Playgroud)
其中一个比另一个更好,它们中的任何一个都有一些可怕的东西,还有一种我还没想过的更好的方法.
我的第一个建议是类似的MooseX::Traits,然后在对象创建时指定不同的角色:
my $test = A->with_traits('Simple::Tax')->new(...);
my $prod = A->with_traits('Complex::Tax')->new(...);
Run Code Online (Sandbox Code Playgroud)
但是,这将打开大门,一个A没有被创建或者被施加作用.所以进一步思考,我认为你有一个X/Y问题.如果Simple::Tax只用于Complex::Tax在测试环境中进行模拟,则可以执行多项操作来覆盖Complex :: Tax实现.
例如,您可以像这样定义Simple :: Tax:
package Simple::Tax;
use Moose::Role;
requires 'calculate_tax';
around calculate_tax => sub { int($_[1]->price * 0.05) };
Run Code Online (Sandbox Code Playgroud)
然后总是有A compose Complex::Tax并且只在测试期间使用Simple :: Tax(使用 apply_all_roles).
但是,如果您在生产中需要Simple :: 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() },
);
Run Code Online (Sandbox Code Playgroud)
然后,如果你想覆盖它,你只需传入一个新的tax_calculator:
my $test = A->new(tax_calculator => SimpleTax::Calculator->new());
my $prod = A->new(tax_calculator => ComplexTax::Calculator->new());
Run Code Online (Sandbox Code Playgroud)
因为handles将角色的所有方法委托为新代理,这几乎与自己编写角色相同.
| 归档时间: |
|
| 查看次数: |
389 次 |
| 最近记录: |