我有一个用Moose构建的类,它本质上是一个文章列表的数据容器.所有属性-样name,number,price,quantity-用于数据."好吧,还有什么?",我能听到你说.还有什么?
不幸的情况的邪恶阴谋现在迫使外部功能进入该包:该类中的数据的税收计算必须由外部组件执行.这个外部组件紧密耦合到整个应用程序,包括破坏组件可测试性的数据库和依赖项,将其拖入一切耦合在一起的炖菜.(即使考虑从炖菜中重构税收成分也是完全不可能的.)
所以我的想法是让类接受包装税计算组件的coderef.然后,该类将保持独立于税收计算实现(及其可能的依赖性噩梦),同时它将允许与应用程序环境集成.
有'tax_calculator',is =>'ro',isa =>'CodeRef';
但是,我已经为我的班级添加了一个非数据组件.为什么这是一个问题?因为我(ab)$self->meta->get_attribute_list用于为我的类组装数据导出:
my %data; # need a plain hash, no objects
my @attrs = $self->meta->get_attribute_list;
$data{ $_ } = $self->$_ for @attrs;
return %data;
Run Code Online (Sandbox Code Playgroud)
现在coderef是属性列表的一部分.当然,我可以过滤掉它.但我不确定我在这里做的任何事情都是一种合理的方式.那么你如何处理这个问题,被认为需要分离数据属性和行为属性?
可能有一半经过深思熟虑的解决方案:使用继承.像今天一样创建你的类,但使用在调用时死亡的calculate_tax方法(即虚函数).然后创建子类,覆盖该方法以调用外部系统.您可以测试基类并使用子类.
备用解决方案:使用角色添加calculate_tax方法.您可以创建两个角色:Calculate :: Simple :: Tax和Calculate :: Real :: Tax.在测试时添加简单角色,在生产中添加真实角色.
我掀起了这个例子,但我没有使用Moose,所以我可能会对如何将角色应用到课堂上感到疯狂.Moosey可能会采用更多方式:
#!/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)
似乎在Moose中使用它的正确方法是使用两个角色.第一个应用于类并包含生产代码.第二个应用于您要在测试中使用的对象.它使用around方法颠覆了第一个方法,并且从不调用原始方法:
#!/usr/bin/perl
use warnings;
{
package Complex::Tax;
use Moose::Role;
requires 'price';
sub calculate_tax {
my $self = shift;
print "complex was called\n";
#pretend this is more complex
return int($self->price * 0.15);
}
}
{
package Simple::Tax;
use Moose::Role;
requires 'price';
around calculate_tax => sub {
my ($orig_method, $self) = @_;
return int($self->price * 0.05);
}
}
{
package A;
use Moose;
has price => ( is => "rw", isa => 'Int' ); #price in pennies
with "Complex::Tax";
}
my $prod = A->new(price => 100);
print $prod->calculate_tax, " cents\n";
use Moose::Util qw/ apply_all_roles /;
my $test = A->new(price => 100);
apply_all_roles($test, 'Simple::Tax');
print $test->calculate_tax, " cents\n";
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
492 次 |
| 最近记录: |