Moose — расширения для Perl 5, позволяющее упростить реализацию ООП.
Создание класса происходит очень легко:
все, пустой класс создан. Он может иметь произвольное количество: аттрибутов, методов, суперклассов, модификаторов метода, конструктор(1шт), деструктор(1шт) и мета-класс(1шт) который содержит все метаинформацию о данном классе.
Теперь подробнее об этих составляющих:
Каждый класс является подклассом Moose::Object. По умолчанию создает кучу всяких полезных объектов, в виде мета-классов и других присущих суперклассу объектов, к которым можно получить доступ после создания.
Наследование происходит с помощью ключевого слова extends
множественное наследование, указываем классы через запятую: extends 'Foo', 'Bar';
Обязательно должно быть имя у аттрибута, может иметь различное количество свойств: флаг read/write, type, accessor method, delegations, значение по умолчанию и др.
По умолчанию Moose хранит аттрибуты в экземпляре класса, как хэш. Доступ к ним можно получить через аксессоры.
has — объявляем аттрибут
опция is может иметь значения [ro|rw|bare] read-only либо read-write или bare — без аксессоров к данному аттрибуту.
predicate — если аттрибут «undef» или другое ложное значение, то возвратит истину.
clearer — сбрасывает аттрибут
clearer — сбрасывает аттрибут
можно установить с помощью свойства: required => 1
по умолчанию все аттрибуты необязательны.
и если не устанавливать в конструкторе, то:
А можно установить ссылку на метод:
Альтернативный метод:
builder рекомендуют использовать вместо default.
этого можно достичь установив свойство: lazy => 1
особенно необходимо, когда начальное значение аттрибута зависит от других факторов.
Еще один плюс в использовании этого свойства, в том что аттрибут будет вычисляться только в том случае, если потребуется, а если же он вообще не потребуется, то мы сохраним CPU time.
могут быть такой же тип как и любая перл структура: isa => 'Str'
а могут быть и объектом: does => 'MyApp::Object'
или так:
Всякая функция, объявленная в классе — это метод класса.
вызываются перед(или «before, after, around, augment») вызовом метода:
поведение или состояние, которое должен реализовать данный класс. Аналог интерфейса в других ООязыках.
Создается с помощью use Moose::Role;
хотя роль выглядит как класс, но это не класс, нельзя создать экземпляр роли. Слово requires говорит нам, что любой класс, использующий данную роль должен реализовать метод 'equal_to'.
Их никогда не нужно явно переопределять, но если все же возникнета такая необходимость то можно использовать BUILD() и DEMOLISH() для конструктора и деструктора соотвественно.
Метакласс описывает класс. С Moose каждый класс дает «meta()», который возвращает Moose::Meta::Class объект. Он говорит о том что представляет из себя данный класс.
происходит если установить в начале класса: use namespace::autoclean;
или в конце класса: no Moose;
Если класс в процессе работы не изменяется, то его работу можно ускорить следущим образом:
Вот и все, этих знаний должно быть достаточно, чтобы успешно создавать ООП структуры на языке Perl, но для более глубокого пониманию, конечно же лучше углубиться в документацию и… да да в исходный код модулей (ну это уж для особых случаев, хотя в данном случае, любопытство никому не помешает).
Создание класса происходит очень легко:
package MyClass; use Moose;
все, пустой класс создан. Он может иметь произвольное количество: аттрибутов, методов, суперклассов, модификаторов метода, конструктор(1шт), деструктор(1шт) и мета-класс(1шт) который содержит все метаинформацию о данном классе.
Теперь подробнее об этих составляющих:
Класс
Каждый класс является подклассом Moose::Object. По умолчанию создает кучу всяких полезных объектов, в виде мета-классов и других присущих суперклассу объектов, к которым можно получить доступ после создания.
Подкласс
Наследование происходит с помощью ключевого слова extends
package User; use Moose; extends 'Person'; has 'username' => ( is => 'rw' );
множественное наследование, указываем классы через запятую: extends 'Foo', 'Bar';
Аттрибуты
Обязательно должно быть имя у аттрибута, может иметь различное количество свойств: флаг read/write, type, accessor method, delegations, значение по умолчанию и др.
По умолчанию Moose хранит аттрибуты в экземпляре класса, как хэш. Доступ к ним можно получить через аксессоры.
has — объявляем аттрибут
has 'first_name' => ( is => 'rw' );
опция is может иметь значения [ro|rw|bare] read-only либо read-write или bare — без аксессоров к данному аттрибуту.
Геттеры и сеттеры можно установить так:
has 'weight' => ( is => 'rw', reader => 'get_weight', writer => 'set_weight', );
predicate — если аттрибут «undef» или другое ложное значение, то возвратит истину.
clearer — сбрасывает аттрибут
clearer — сбрасывает аттрибут
has 'ssn' => ( is => 'rw', clearer => 'clear_ssn', predicate => 'has_ssn', );
$person->has_ssn; # false $person->ssn(undef); $person->ssn; # returns undef $person->has_ssn; # true $person->clear_ssn; $person->ssn; # returns undef $person->has_ssn; # false $person->ssn('123-45-6789'); $person->ssn; # returns '123-45-6789' $person->has_ssn; # true
Необходимость в установки аттрибута
можно установить с помощью свойства: required => 1
по умолчанию все аттрибуты необязательны.
Аттрибуты можно установить по умолчанию двумя способами.
has 'size' => ( is => 'ro', default => 'medium', predicate => 'has_size', );
и если не устанавливать в конструкторе, то:
my $person = Person->new(); $person->size; # medium $person->has_size; # true
А можно установить ссылку на метод:
has 'size' => ( is => 'ro', default => sub { ( 'small', 'medium', 'large' )[ int( rand 3 ) ] }, predicate => 'has_size', );
Альтернативный метод:
has 'size' => ( is => 'ro', builder => '_build_size', predicate => 'has_size', ); sub _build_size { return ( 'small', 'medium', 'large' )[ int( rand 3 ) ]; }
builder рекомендуют использовать вместо default.
Откладываем установку аттрибута в последнюю очередь
этого можно достичь установив свойство: lazy => 1
особенно необходимо, когда начальное значение аттрибута зависит от других факторов.
Еще один плюс в использовании этого свойства, в том что аттрибут будет вычисляться только в том случае, если потребуется, а если же он вообще не потребуется, то мы сохраним CPU time.
Типы аттрибутов
могут быть такой же тип как и любая перл структура: isa => 'Str'
а могут быть и объектом: does => 'MyApp::Object'
Установка нескольких аттрибутов
has [ 'x', 'y' ] => ( is => 'ro', isa => 'Int' );
или так:
for my $name ( qw( x y ) ) { my $builder = '_build_' . $name; has $name => ( is => 'ro', isa => 'Int', builder => $builder ); }
Методы
Всякая функция, объявленная в классе — это метод класса.
Модификаторы методов
вызываются перед(или «before, after, around, augment») вызовом метода:
before 'atribute' => sub { my $self = shift; my $a = shift; print $a; };
Роль
поведение или состояние, которое должен реализовать данный класс. Аналог интерфейса в других ООязыках.
Создается с помощью use Moose::Role;
package Eq; use Moose::Role; requires 'equal_to'; sub not_equal_to { my ( $self, $other ) = @_; not $self->equal_to($other); }
хотя роль выглядит как класс, но это не класс, нельзя создать экземпляр роли. Слово requires говорит нам, что любой класс, использующий данную роль должен реализовать метод 'equal_to'.
package Comparable; use Moose; with 'Eq'; sub equal_to { my ( $self, $other ) = @_; $self->compare($other) == 0; } sub compare { my ( $self, $other ) = @_; $self->amount <=> $other->amount; }
Конструктор/Деструктор
Их никогда не нужно явно переопределять, но если все же возникнета такая необходимость то можно использовать BUILD() и DEMOLISH() для конструктора и деструктора соотвественно.
Metaclass
Метакласс описывает класс. С Moose каждый класс дает «meta()», который возвращает Moose::Meta::Class объект. Он говорит о том что представляет из себя данный класс.
my $meta = User->meta(); for my $attribute ( $meta->get_all_attributes ) { print $attribute->name(), "\n"; if ( $attribute->has_type_constraint ) { print " type: ", $attribute->type_constraint->name, "\n"; } } for my $method ( $meta->get_all_methods ) { print $method->name, "\n"; }
Очистка мусора
происходит если установить в начале класса: use namespace::autoclean;
или в конце класса: no Moose;
Ускорение работы классов
Если класс в процессе работы не изменяется, то его работу можно ускорить следущим образом:
__PACKAGE__->meta->make_immutable;
Вот и все, этих знаний должно быть достаточно, чтобы успешно создавать ООП структуры на языке Perl, но для более глубокого пониманию, конечно же лучше углубиться в документацию и… да да в исходный код модулей (ну это уж для особых случаев, хотя в данном случае, любопытство никому не помешает).