Perl 初始化后,我应该如何定义Moose对象子例程?

Perl 初始化后,我应该如何定义Moose对象子例程?,perl,initialization,moose,Perl,Initialization,Moose,初始化后,我应该如何定义Moose对象子例程 我正在使用Moose编写一个对象模块,并计划序列化(nstore)创建的对象 检查以下(简化!)示例: 包装MyObj 0.001; 使用驼鹿; 使用namespace::autoclean; 具有“大小”=>( is=>“ro”, isa=>Int', 必需=>1, ); sub some_sub{ 我的($self,@more)=; 如果($self->size()size()size()selected子系统(@)。你觉得怎么样?也许是另一种情

初始化后,我应该如何定义Moose对象子例程

我正在使用Moose编写一个对象模块,并计划序列化(
nstore
)创建的对象

检查以下(简化!)示例:

包装MyObj 0.001;
使用驼鹿;
使用namespace::autoclean;
具有“大小”=>(
is=>“ro”,
isa=>Int',
必需=>1,
);
sub some_sub{
我的($self,@more)=;
如果($self->size()<100)#做点什么;
elsif(($self->size()<500))#做点别的;
elsif(($self->size()<7500))#做点别的;
# ...
}
1.
根据
大小的不同,某些\u sub
的作用也不同。由于
size
是只读的,因此在初始化对象后它保持不变

因此,假设我调用了无数次
if
s,很遗憾每次我都要经历所有
if
s

我最好在对象初始化后执行一次,然后将
some\u sub
设置为一个更简单的函数,如果
s,则不使用

但是。。。我该怎么做

更新

也许我应该添加subref类型的
lazy
属性,该属性将保存对所选子例程的引用
一些子系统
然后只需调用
$self->selected子系统(@)
。你觉得怎么样?

也许是另一种情况!(对不起,我按相反的顺序阅读你的问题!)

例如:

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
使用5.012;
使用警告;
包装MyObj 0.001;
使用MooseX::SingletonMethod;
使用namespace::autoclean;
具有“大小”=>(
is=>“ro”,
isa=>Int',
必需=>1,
);
sub\u哪个sub{
我的($self)=@;
如果($self->size<100){return sub{'A'}
elsif($self->size<500){return sub{'B'}
elsif($self->size<7500){return sub{'C'}
返回子{'D'};
}
主包装;
my$obj=MyObj->new(大小=>200);
$obj->add_singleton_方法(some_sub=>$obj->\u which_sub);
说$obj->some#sub;#=>B

应该可以从类内部添加这个单一的方法创建。请查看此博客文章以获得一些指导:。还有一大堆关于你的更新的帖子

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
使用5.012;
使用警告;
包装材料MyObj;
使用驼鹿;
使用namespace::autoclean;
具有“大小”=>(
is=>“ro”,
isa=>Int',
必需=>1,
);
已“选择_sub”=>(
is=>“ro”,
isa=>CodeRef',
懒惰=>1,
builder=>“\u build\u selected\u sub”,
init_arg=>undef,#除非希望在构造时提供一个非子节点选项?
);
子组件(构建)(选定)(子组件){
我的($self)=@;
如果($self->size<100){return sub{'A'}
elsif($self->size<500){return sub{'B'}
elsif($self->size<7500){return sub{'C'}
返回子{'D'};
}
主包装;
my$obj=MyObj->new(大小=>200);
说$obj->selected_sub->();#=>B
有计算方法=>(is=>'ro',lazy\u build=>1,init\u arg=>undef);
子构建计算方法{
我的$self=shift;
如果$self->size<100,则返回“\u calculate\u small”;
如果$self->size<500,则返回“\u calculate\u medium”;
如果$self->size<7500,则返回“\u calculate\u large”;
返回“_计算_巨大”;
}
子计算小{…}
子计算介质{…}
#等等。
子计算{
我的$self=shift;
my$method=$self->calculation\u method;
返回$self->$method(@);
}

另外,
calculation\u方法
现在也可以序列化了。

我不太喜欢它,因为我希望它对用户透明。这一切都应该在对象初始化期间发生。另请参阅我的更新,了解我对它的另一种看法。它可以做到这一点(提供的链接提供了一些关于这一点所需的重播的见解)。但是,如果您对
$self->selected\u sub->(@))满意(@))
(关于:您的更新),那么请查看我的新答案。是否有理由我不满意
$self->selected\u sub->(@))
。仅参考API,即使用
$obj->selected_sub->(…)
而不是
$obj->selected_sub(…)
顺便说一句,我认为构建器解决方案是最好的方法。请注意,本机代码属性trait具有“execute”和“execute\u method”委托,可用于轻松设置CodeRef属性,其行为类似于普通方法。@phaylon:很酷,以前从未见过这种情况。现在有了!。。。我认为您可以将'selected_sub'设为private(即更改为
\u selected_sub
),然后添加
sub mysub{my($self)=@;返回$self->\u selected_sub()->(@)}
。现在我们可以调用
$obj->mysub()。再看看,这就是hdp写的。是的,hdp的答案是最好的(+1)。我也在考虑写同样的东西,但目的是让它更接近你的更新,也就是说,我认为你想要/需要在他们的+1中使用anon sub。是的,这就是我更新的内容。您还可以将
calculate()
方法折叠到
calculate\u method
属性中(并将其重命名为
s/\u method/
),方法是使其
isa=>'CodeRef',traits=>['code'],handles=>{calculate=>'execute\u method'})(正如费伦在德雷顿的回答中指出的那样)。
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
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(@_);
}