我在Perl练习Kata Nine: Back to the CheckOut,同时也是第一次尝试使用Moose。
到目前为止,我已经创建了以下类:
package Checkout;
# $Id$
#
use strict;
use warnings;
our $VERSION = '0.01';
use Moose;
use Readonly;
Readonly::Scalar our $PRICE_OF_A => 50;
sub price {
my ( $self, $items ) = @_;
if ( defined $items ) {
$self->{price} = 0;
if ( $items eq 'A' ) {
$self->{price} = $PRICE_OF_A;
}
}
return $self->{price};
}
__PACKAGE__->meta->make_immutable;
no Moose;
1;
整个price
方法感觉不是非常愚蠢,我觉得这可以进一步重构。
有没有人对如何改进这方面有任何意见?
答案 0 :(得分:8)
我注意到的第一件事是你没有使用显式属性 类。
$self->{price} = 0;
这违反了使用Moose提供的大部分封装。麋鹿解决方案
会在至少将price
变为实际属性。
use 5.10.0; # for given/when
has '_price' => ( is => 'rw' );
sub price {
my ( $self, $item ) = @_;
given ($item) {
when ('A') { $self->_price($PRICE_OF_A) }
default { $self->_price(0) }
}
}
然而,您提供的代码的主要问题是您不是 真正模拟了卡塔所描述的问题。首先是卡塔 说明你需要在每次调用时传递定价规则 结帐对象。所以我们知道我们需要将这种状态保存在其他东西中 而不是一系列ReadOnly类变量。
has pricing_rules => (
isa => 'HashRef',
is => 'ro',
traits => ['Hash'],
default => sub { {} },
handles => {
price => 'get',
has_price => 'exists'
},
);
你会看到这里的价格方法现在是使用Moose的“Native”的委托 属性“委托。这将在项目和规则之间执行查找。 但是,这不会处理查找没有的元素的情况 存在。向前看,Kata提供的其中一个单元测试就是这样 一种查找:
is( price(""), 0 ); # translated to Test::More
因此,我们需要稍微修改价格方法来处理这种情况。 基本上我们检查是否有价格规则,否则我们返回0.
around 'price' => sub {
my ( $next, $self, $item ) = @_;
return 0 unless $self->has_price($item);
$self->$next($item);
};
接下来,我们需要跟踪扫描的项目,以便我们可以构建总计。
has items => (
isa => 'ArrayRef',
traits => ['Array'],
default => sub { [] },
handles => {
scan => 'push',
items => 'elements'
},
);
“Native Attributes”委托再次提供了scan
方法
卡塔的考试正在寻找。
# Translated to Test::More
my $co = Checkout->new( pricing_rules => $RULES );
is( $co->total, 0 );
$co->scan("A");
is( $co->total, 50 );
最后,使用total
的{{1}}函数,List::Util
方法很简单。
sum
此代码并未完全实现Kata的解决方案,但确实如此 提出一个更好的问题状态模型,并显示更多 “Moosey”解决方案。
完整的代码和翻译的测试如下所示。
sub total {
my ($self) = @_;
my @prices = map { $self->price($_) } $self->items;
return sum( 0, @prices );
}
答案 1 :(得分:2)
可以删除use strict;
和use warnings;
,因为use Moose;
已经为您执行此操作。您也可以使用Moose创建只读属性,而不是使用Readonly
模块。
package Checkout;
# $Id$
#
our $VERSION = '0.01';
use Moose;
has '_prices' => (
is => 'ro',
isa => 'HashRef',
lazy_build => 1,
init_arg => undef, # do not allow in constructor
);
sub _build__prices {
my ( $self ) = @_;
return {
'A' => 50
};
}
sub price {
my ( $self, $items ) = @_;
return (exists $self->_prices->{$items} ? $self->_prices->{$items} : 0);
}
__PACKAGE__->meta->make_immutable;
no Moose;
1;