Пару раз встречал оригинальные варианты создания объектов в любимом Perl и вздохи по поводу 6-ки, что там все проще, лучше, быстрее и т.п. Однако довольно симпатичные и совершенно безопасные конструкции можно городить и в «народной» пятерке. Используем классический вариант из учебника с замыканиями и горкой перца :)
Итак, дабы не затягивать и не смущать гуру — сразу привожу код, объяснения будут под ним:
Получаем замечательный пакет для создания объектов совершенно классическим методом:
"- Что за нафик репринт учебника?" — спросите Вы.
Ну, на самом деле пара отличий от учебника есть —
А вся конструкция получается ажурной и прочной — попытка «прикрутить» свойство, нами не предусмотренное, даст уже фатальную ошибку с указанием на место в коде пользователя (модуля) силами самого Perl.
ИМХО гораздо «прозрачнее» использования «больших» модулей-оберток ООП-функций.
PS. Совершенно очевидно, что ничто не мешает нам сделать некоторые свойства RO — добавляем в замыкание проверку типа:
и отсекаем write-обращения к RO свойствам снаружи, оставив только внутреннее обращение (мы же хотим работать с этим свойством?).
UP. По мотивам этого топика родился полуфабрикат Botox — просто скопируйте и используйте с умом.
Итак, дабы не затягивать и не смущать гуру — сразу привожу код, объяснения будут под ним:
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");
"- Что за нафик репринт учебника?" — спросите Вы.
Ну, на самом деле пара отличий от учебника есть —
- мы совершенно спокойно передаем параметры нового объекта конструктору сразу
- мы совершенно спокойно позволяем передавать конструктору параметры с ошибкой — объект все равно будет создан (со всеми валидными свойствами), а пользователь (модуля) получит сообщение, что он пытался установить неизвестное свойство. Возможно это наведет его на мысль почитать документацию по модулю.
А вся конструкция получается ажурной и прочной — попытка «прикрутить» свойство, нами не предусмотренное, даст уже фатальную ошибку с указанием на место в коде пользователя (модуля) силами самого Perl.
ИМХО гораздо «прозрачнее» использования «больших» модулей-оберток ООП-функций.
PS. Совершенно очевидно, что ничто не мешает нам сделать некоторые свойства RO — добавляем в замыкание проверку типа:
if (__PACKAGE__ eq (caller)) {#inner call}
и отсекаем write-обращения к RO свойствам снаружи, оставив только внутреннее обращение (мы же хотим работать с этим свойством?).
UP. По мотивам этого топика родился полуфабрикат Botox — просто скопируйте и используйте с умом.