【问题标题】:How should I define a Moose object subroutine after its initialization?我应该如何在初始化后定义 Moose 对象子例程?
【发布时间】:2010-10-22 10:42:00
【问题描述】:

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 无数次,很遗憾我每次都必须通过所有ifs。

我最好在对象初始化后执行一次,然后将some_sub 设置为一个更简单的函数,根本没有ifs。

但是……我该怎么做呢?

更新

也许我应该添加一个 subref 类型的lazy 属性,它将保存对所选子例程的引用。然后some_sub 将简单地调用$self-&gt;chosen_sub-&gt;(@_)。你怎么看?

【问题讨论】:

    标签: perl initialization moose


    【解决方案1】:
    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 是的,这就是我的更新内容。只是想确保它有意义。
    • 您还可以将calculate() 方法折叠到calculation_method 属性中(并重命名为s/_method//),方法是使其成为isa =&gt; 'CodeRef', traits =&gt; ['Code'], handles =&gt; { calculate =&gt; 'execute_method' });(正如phaylon 在draegtun 的回答中指出的那样)。
    【解决方案2】:

    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

    【讨论】:

    • 我不太喜欢它,因为我希望它对用户透明。这一切都应该在对象初始化期间发生。另请参阅我的更新以获取其他信息。
    • 它可以变得如此透明(提供的链接提供了一些关于此所需的重新祝福的见解)。但是,如果您对 $self-&gt;chosen_sub-&gt;(@_) 满意(回复:您的更新),请查看我的新答案。
    • 有什么理由我不应该接受$self-&gt;chosen_sub-&gt;(@_)
    • 不。仅指API,即。很高兴使用$obj-&gt;chosen_sub-&gt;(...) 而不是$obj-&gt;chosen_sub(...)
    • 顺便说一句,我认为构建器解决方案是解决此问题的最佳方法。
    【解决方案3】:

    关于您的更新:

    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
    

    【讨论】:

    • 请注意,本机 Code 属性 trait 具有 'execute' 和 'execute_method' 委托,可用于轻松设置 CodeRef 属性,其作用类似于常用方法。
    • @phaylon:很酷,以前没见过。现在有!...search.cpan.org/dist/Moose/lib/Moose/Meta/Attribute/Native/…
    • 我认为您可以将“chosen_sub”设为私有(即更改为_chosen_sub)然后添加sub mysub { my ($self) = @_; return $self-&gt;_chosen_sub()-&gt;(@_);}。现在我们可以拨打$obj-&gt;mysub();。再看一遍,这就是 hdp 写的。
    • 是的 hdp 答案是最好的答案 (+1)。我正在考虑写相同的内容,但旨在使其更接近您的更新,即。我以为你想要/需要他们的匿名潜艇。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    相关资源
    最近更新 更多