如何使我的Perl方法更像Moose?

时间:2010-10-26 12:06:03

标签: perl moose

我在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方法感觉不是非常愚蠢,我觉得这可以进一步重构。

有没有人对如何改进这方面有任何意见?

2 个答案:

答案 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;