Как стать автором
Обновить

Эффектное создание объектов в Perl

Время на прочтение2 мин
Количество просмотров955
Пару раз встречал оригинальные варианты создания объектов в любимом Perl и вздохи по поводу 6-ки, что там все проще, лучше, быстрее и т.п. Однако довольно симпатичные и совершенно безопасные конструкции можно городить и в «народной» пятерке. Используем классический вариант из учебника с замыканиями и горкой перца :)


Итак, дабы не затягивать и не смущать гуру — сразу привожу код, объяснения будут под ним:

package Person;

use Carp;
use strict;

my ($init,$setup);

sub new {
  my $invocant = shift;
  my $self = bless({}, ref $invocant || $invocant);
  $self->$init();
  $self->$setup(@_);
  return $self;
}

$init = sub {
  my $self = shift;
  $self->name("unnamed"); # end e.t.c
 
};

for my $field (qw(name race aliases)) {
  my $slot = __PACKAGE__ . "::$field";
  no strict "refs";     # So symbolic ref to typeglob works.
  *$field = sub {
    my $self = shift;
    $self->{$slot} = shift if @_;
    return $self->{$slot};
  };
}

$setup = sub {
  my $self = shift;
  my %var = @_;  
  no strict "refs";
  foreach (keys %var) {
    if (*$_{CODE})  {$self->$_($var{$_});}
    else {carp (qq{Haven`t properties "$_" in object }.__PACKAGE__." ");}      
  }
};


* This source code was highlighted with Source Code Highlighter.


Получаем замечательный пакет для создания объектов совершенно классическим методом:

my $mage = Person->new(name=>"Gandalf",race=>"Istar");


"- Что за нафик репринт учебника?" — спросите Вы.

Ну, на самом деле пара отличий от учебника есть —
  1. мы совершенно спокойно передаем параметры нового объекта конструктору сразу
  2. мы совершенно спокойно позволяем передавать конструктору параметры с ошибкой — объект все равно будет создан (со всеми валидными свойствами), а пользователь (модуля) получит сообщение, что он пытался установить неизвестное свойство. Возможно это наведет его на мысль почитать документацию по модулю.


А вся конструкция получается ажурной и прочной — попытка «прикрутить» свойство, нами не предусмотренное, даст уже фатальную ошибку с указанием на место в коде пользователя (модуля) силами самого Perl.

ИМХО гораздо «прозрачнее» использования «больших» модулей-оберток ООП-функций.

PS. Совершенно очевидно, что ничто не мешает нам сделать некоторые свойства RO — добавляем в замыкание проверку типа:
if (__PACKAGE__ eq (caller)) {#inner call}

и отсекаем write-обращения к RO свойствам снаружи, оставив только внутреннее обращение (мы же хотим работать с этим свойством?).

UP. По мотивам этого топика родился полуфабрикат Botox — просто скопируйте и используйте с умом.
Теги:
Хабы:
+10
Комментарии7

Публикации

Изменить настройки темы

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн