如何在初始化后定义Moose对象子程序?
我正在使用Moose编写一个对象模块,我计划序列化(nstore
)创建的对象。
检查以下(简化!)示例:
package MyObj 0.001;
use Moose;
use namespace::autoclean;
has 'size' => (
is => 'ro',
isa => 'Int',
required => 1,
);
sub some_sub {
my ($self, @more) = @_;
if ($self->size() < 100) # do something;
elsif (($self->size() < 500)) # do something else;
elsif (($self->size() < 7500)) # do something else;
# ...
}
1;
some_sub
的行为取决于size
。由于size
是只读的,因此在初始化对象后它保持不变。
所以,假设我拨打some_sub
次,我很遗憾每次都必须经历所有if
次。
我最好在初始化对象后执行此操作,然后将some_sub
设置为更简单的函数,而根本没有if
。
但是......我怎么能这样做?
更新
也许我应该添加一个类型为subref的lazy
属性,该属性将保存对所选子例程的引用。然后,some_sub
会致电$self->chosen_sub->(@_)
。你觉得怎么样?
答案 0 :(得分:5)
has calculation_method => (is => 'ro', lazy_build => 1, init_arg => undef);
sub _build_calculation_method {
my $self = shift;
return '_calculate_small' if $self->size < 100;
return '_calculate_medium' if $self->size < 500;
return '_calculate_large' if $self->size < 7500;
return '_calculate_enormous';
}
sub _calculate_small { ... }
sub _calculate_medium { ... }
# etc.
sub calculate {
my $self = shift;
my $method = $self->calculation_method;
return $self->$method(@_);
}
作为奖励,calculation_method
现在也可以序列化。
答案 1 :(得分:0)
也许MooseX::SingletonMethod的另一个案例! (对不起,我正在按相反的顺序阅读你的问题!)。
例如:
use 5.012;
use warnings;
package MyObj 0.001;
use MooseX::SingletonMethod;
use namespace::autoclean;
has 'size' => (
is => 'ro',
isa => 'Int',
required => 1,
);
sub _which_sub {
my ($self) = @_;
if ($self->size < 100) { return sub{ 'A' } }
elsif ($self->size < 500) { return sub{ 'B' } }
elsif ($self->size < 7500) { return sub{ 'C' } }
return sub { 'D' };
}
package main;
my $obj = MyObj->new( size => 200 );
$obj->add_singleton_method( some_sub => $obj->_which_sub );
say $obj->some_sub; # => B
并且应该可以在类中添加此单个方法创建。请查看此博客文章以获取一些指导:Moose Singleton Method: Now without roles!。还有帖子here
答案 2 :(得分:0)
关于您的更新:
use 5.012;
use warnings;
package MyObj;
use Moose;
use namespace::autoclean;
has 'size' => (
is => 'ro',
isa => 'Int',
required => 1,
);
has 'chosen_sub' => (
is => 'ro',
isa => 'CodeRef',
lazy => 1,
builder => '_build_chosen_sub',
init_arg => undef, # unless want option of providing anon sub at construction?
);
sub _build_chosen_sub {
my ($self) = @_;
if ($self->size < 100) { return sub{ 'A' } }
elsif ($self->size < 500) { return sub{ 'B' } }
elsif ($self->size < 7500) { return sub{ 'C' } }
return sub { 'D' };
}
package main;
my $obj = MyObj->new( size => 200 );
say $obj->chosen_sub->(); # => B