2012-03-02 6 views
14

Я понимаю, что использование builder позволяет подклассам легко переопределять атрибуты по умолчанию, а роли могут быть require. Это также может быть достигнуто с помощью default так:Moose «builder» vs «default»

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

мне интересно, если есть дополнительные преимущества для использования builder я не знаю? Я пришел с каким-то себе:

  • builder декларативно, так что вы можете самоанализом, что foo построен _build_foo
  • builder устраняет подпрограмму оболочки, что делает его немного быстрее
  • builder позволяет использование полезный lazy_build.

UPDATE Чтобы уточнить, это не про default против builder в целом, но default => sub { $_[0]->_build_foo } против builder => '_build_foo'.

ответ

12

Думаю, вы уже ответили на свой вопрос. Использование builder допускает позднюю привязку, которая прекрасно сочетается с ролями и классами, которые предназначены для подкласса. Также полезно, если строитель довольно длинный - я никогда не ставил default больше, чем линию в определение атрибута. Там нет реальной функциональной разницы; default может легко эмулировать builder, но результат не очень красивый.

+0

Почему вы думаете, что 'default => \ & builder' не выполняет каждую из этих вещей? – ikegami

+2

@ikegami, потому что '' & builder' будет разрешен для '& builder' в текущем пакете. Подкласс, который предоставляет новый 'builder', должен был бы снова использовать' has '+ attr' => builder => \ & builder', чтобы привязать его к переопределенному методу. OTOH 'builder => 'builder'' разрешен во время выполнения. – hobbs

+0

В качестве контрапункта подкласс может переопределить атрибут и изменить «default». Это не требует знания имени метода private builder. * Оба * требуют знать, использует ли атрибут 'default' или' builder', потому что вы не можете иметь оба. Это, как правило, частная информация и может быть изменена. Переопределение поведения атрибутов в Moose по умолчанию является проблематичным, вам нужно публиковать сведения о том, как это поведение по умолчанию реализовано, или подкласс должен инспектировать. :/ – Schwern

3

Там нет никакой разницы между

default => sub { $_[0]->_build_foo } 

и

builder => '_build_foo' 

Основным различием между default и builder является то, что один один называет Анон к югу, а другие называют по имени метода.

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

против

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

sub _build_created_time_stamp { time() } 

Использования default уменьшает прокрутку коды, как все, где вам это нужно. Я использую его по этой причине. То есть использование менее типизации является бонусом.

Это также заставляет вас более четко описывать переопределение строителя. Другие ответы рассматривали этот конфликт, но я считаю, что вызов виртуальных методов на объекте, который еще не был сконструирован, является плохой практикой! Вот для чего BUILD.

+0

Вопрос в частности о 'default => sub {$ _ [0] -> _ build_foo}' vs 'builder => '_build_foo'', поэтому подклассы могут переопределять стандартный, а не стандартный vs-конструктор по умолчанию. Вот почему дополнительный подзаголовок. – Schwern

+0

@ Шверн, Зачем ты это делаешь ?! Нет причин делать это вообще. Ну, может быть, для согласованности, если вы использовали 'default' везде. – ikegami

+2

«Зачем вы это делаете» именно так я и спрашиваю. Мне кажется, что 'builder => '_build_foo'' является синтаксическим сахаром для' default => sub {$ _ [0] -> _ build_foo} '. Есть что-то еще? – Schwern

4

Использование «строителя» и «по умолчанию» позволяет сделать код более удобным для чтения и организации.

«Строитель» также может соответствовать знакомому шаблону программирования, где частные методы начинаются с подчеркивания.

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 }; 

Refactor с запоминанием:

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

Это большинство способов Я использовал построитель для уточнения кода.

+0

Я также хотел бы использовать их для атрибутов в словах, роли, которые кто-то может захотеть переопределить в классе, потребляющем указанную роль. Кажется немного проще, чем переопределить весь атрибут с «+» перед именем. – dhoss

+0

Извините, это не про 'builder' vs' default' вообще, а 'default => sub {$ _ [0] -> _ build_foo}' vs 'builder => '_build_foo''. – Schwern

Смежные вопросы