Моим первым предложением было бы что-то вроде 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.
Например, вы можете просто определить Simple :: Tax следующим образом:
package Simple::Tax;
use Moose::Role;
requires 'calculate_tax';
around calculate_tax => sub { int($_[1]->price * 0.05) };
Тогда всегда A составляет Complex::Tax
и применяет Simple :: Tax к нему только во время тестов (используя apply_all_roles
).
Если, тем не менее, вам нужны Simple :: Tax и Complex :: Tax как в производстве (так и не просто для тестирования), то вам лучше всего делать рефакторинг из отношения композиции (делает) к отношениям делегирования (имеет).
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
будет делегировать все методы из роли в качестве новых проксиэто практически то же самое, что составить роль самостоятельно.