如何在初始化后定义Moose对象子程序?

时间:2010-10-22 10:42:00

标签: perl initialization moose

如何在初始化后定义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->(@_)。你觉得怎么样?

3 个答案:

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