5. Великий и могучий Moose
В описании Moose говориться следующее:
Основная цель Moose заключается в том, чтобы сделать ООП в Perl 5легче, более устойчивым и менее утомительным. С Moose вы можете думать больше о том, что вы хотите сделать, и меньше о механике ООП.
Пример использования Moose (иногда еще говорят «классов в стиле Modern Perl»):
#!/usr/bin/perl
package MyClass; {
use strict;
use Moose;
use MooseX::Privacy;
# объявляем новое свойство
# строка, только для чтения, по умолчанию - "Anonymous"
has 'name' => (
is => 'ro',
isa => 'Str',
default => 'Anonymous',
);
# аналогично, но это свойство - protected
has 'version' => (
is => 'ro',
isa => 'Str',
default => '1.0',
traits => [qw/Protected/], # или Private
);
# или protected_method
private_method print_info => sub {
my($self, $format, $params) = @_;
printf $format."\n", $self->{name};
if(scalar keys %{$params}) {
print "Params:\n";
for my $k(keys %{$params}) {
print " $k => $params->{$k}\n";
}
}
}; # нужна точка с запятой!
sub BUILD {
my($self, $params) = @_;
$self->print_info(
'MyClass with name %s created!',
$params
);
}; # тут точка с запятой вообще-то не нужна,
# но чтобы гарантированно не накосячить,
# лучше ставить ее везде
}
1; # ok!
Пример класса-наследника:
#!/usr/bin/perl
package MyClassChild; {
use strict;
use Moose;
extends 'MyClass';
# новое свойство
has 'second_name' => (
is => 'ro',
isa => 'Str',
default => 'Anonymous',
);
# изменяем унаследованное свойство
has '+version' => (
default => '1.1',
);
sub BUILD {
my($self, $args) = @_;
print "Child's version is $self->{version}\n";
}
}
1;
Пример использования этих классов — точно такой же, как и в предыдущем пункте.
В Moose реализовано все возможности, предлагаемые большинством современных ООП языков. Модуль снабжен прекрасной документацией (см Moose::Cookbook). Также был обнаружен очень интересный модульMooseX::Declare, добавляющий немного синтаксического сахара в Moose. К сожалению, на момент написания этих строк, он был несовместим с MooseX::Privacy.
См также пост на Хабре, посвященный Moose.
6. Модуль Perl6::Classes
И последний модуль, рассматриваемый в этой заметке — Perl6::Classes. Он представляет собой попытку перенести в Perl 5 возможности и синтаксис Perl 6, связанные с ООП.
#!/usr/bin/perl
use strict;
use Perl6::Classes;
class Human {
has $.name; # все свойства - закрытые; это - хорошая практика
method BUILD {
$.name = shift;
}
method get_name {
return $.name;
}
method test_protected is protected {
}
method test_private is private {
}
# Разница между method и sumbethod в том, что последний
# не наследуется потомками. Если сделать этот метод
# наследуемым, в дочерних классах он будет вызван дважды.
submethod DESTRUCT {
print "Destroying $.name\n";
}
}
# проверка наследования
class Developer is Human {
method test {
$self->test_protected();
# $self->test_private();
}
submethod DESTRUCT {
print "Developer's destructor...\n";
}
}
# проверка полиморфизма
# ( я с трудом могу представить ситуацию, где в Perl
# требовались бы _виртуальные_ методы )
sub polymorph_test {
my ($obj) = @_;
return $obj->get_name();
}
my $human = Human->new("Alex");
my $dev = Developer->new("Afiskon");
$dev->test();
print "Developer's name: ".polymorph_test($dev)."\n";
print "Human's name: ".polymorph_test($human)."\n";
Этот модуль прекрасно иллюстрирует расширяемость синтаксиса Perl, но, к сожалению, не применим на практике из-за наличия нескольких серьезных багов (см описание в CPAN). Судя по тому, что модуль не обновляется с 2003-го года, работа над ним остановлена.
