穆斯“建设者”与“默认”

时间:2012-03-02 00:26:55

标签: perl moose

我知道使用builder可以让子类轻松覆盖属性默认值,角色可以require。这也可以使用default完成,如下所示:

has 'foo' =>
    is       => 'rw',
    isa      => 'Str',
    default  => sub { $_[0]->_build_foo };

我想知道使用builder是否还有其他优点我不知道?我自己想出了一些:

  • builder是声明性的,因此您可以反省foo_build_foo
  • 构建
  • builder消除了子程序包装,使其更快一点
  • builder允许使用有用的lazy_build

更新要澄清一下,这与defaultbuilder的关系一般,default => sub { $_[0]->_build_foo }builder => '_build_foo'无关。

3 个答案:

答案 0 :(得分:12)

我想你已经回答了自己的问题。使用builder允许后期绑定,它可以很好地与要创建子类的角色和类一起使用。如果构建器很长,那么它也很有价值 - 我从来没有在属性定义中添加多行default。没有真正的功能差异; default可以轻松模拟builder,但效果不是很好。

答案 1 :(得分:4)

适当地使用“构建器”和“默认”可以使代码更易于阅读和组织。

'builder'也可以适合熟悉的编程模式,其中私有方法以下划线开头。

has json => ( is => 'ro', default => sub { JSON->new } )
has schema => ( is => 'ro', builder => '_schema' }

sub _schema {
  my $self = shift;
  $self->log_debug('constructing schema') if($self->debug);
  My::App::Schema->connect($self->dsn,$self->username,$self->password)  
}

此外,使用构建器可以将昂贵的函数转换为memoized访问器,而无需触及原始方法:

sub get_things {
  my $self = shift;
  return +{ map { $_ => $self->price_for($_) }
    $self->wodgets->calulate_expensive_things };

带有记忆的重构:

has things => ( is => 'ro', lazy => 1, builder => 'get_things' );

这些是我使用构建器澄清我的代码的大多数方法。

答案 2 :(得分:3)

之间没有区别
default => sub { $_[0]->_build_foo }

builder => '_build_foo'

defaultbuilder之间的主要区别在于,一个调用anon sub,另一个调用named方法。

has created_time_stamp => (
   default => sub { time() },
);

has created_time_stamp => (
   builder => '_build_created_time_stamp',
);

sub _build_created_time_stamp { time() }

使用default可以减少代码的滚动,因为一切都在您需要的地方。我出于这个原因使用它。使用较少的打字是一种奖励。

它还会迫使您更明确地覆盖构建器。其他答案已经认为这是一个骗局,但我考虑在一个尚未构建的对象上调用虚拟方法,这仍然是一个不好的做法!这就是BUILD的用途。