Что такое Moose в Perl. Руководство для начинающих

Что такое Moose в perl. Для чего нужен Moose. Как его использовать. Функции Moose. Классы, роли, атрибуты, объекты Moose и т.д. Введение в Moose для начинающих.

Moose переводится с английского как «американский лось». Это название идет к нему как нельзя лучше. Большая и суровая корова. Молока не будет, по рогам получите. Ну вы поняли, как я к нему отношусь :)

moose

Общепринятое определение: Moose — это расширение для Perl 5, которое позволяет упростить реализацию ООП.

Moose позволяет создавать простые классы без написания подпрограмм и упрощать сложные классы. Moose позволяет использовать такие новые для perl понятия, как роли, интерфейсы и атрибуты. Можно использовать метаклассы. Moose имеет множество расширений, которые распространяются в модулях MooseX .

Лично мое мнение: Moose имеет слишком чужеродный для perl синтаксис и идеологию, что значительно усложняет программистам понимание написанного с его помощью кода. В результате, некоторая экономия времени и дискового пространства при разработке, оборачивается убытками при последующей поддержке.

Но, т.к. иногда в ИТ-компаниях Moose все-таки используется, лучше его знать.

Moose работает на основе Class::MOP, который является системой метаклассов для perl 5. Это означает, что можно использовать Moose не только для оптимизации ООП, но и для разработки метаклассов.

Moose подключает Moose::Meta::Class, который является метаклассом, и подклассом Class::MOP::Class. Moose экспортирует несколько функций: extends, with, has, before, after, around, override, augment.

Как создать класс в Moose

Moose позволяет программисту создавать классы, которые могут иметь атрибуты, роли, методы, модификаторы методов, родительсткие классы (суперклассы). Каждый класс имеет собственный конструктор и деструктор.

Вот так выглядит самый простой класс на основе Moose:

Создание конструктора осуществляется Moose автоматически, а наличие других методов не являются обязательным условием для создания рабочего класса.

Обычно для создания объекта использовались методы new(). Это было негласным стандартом. Теперь создание экземпляра класса осуществляется внутри Moose, автоматически. Если необходимо, можно определить метод BUILD() в своем классе. Метод будет вызываться Moose сразу после создания объекта.

В стандартном perl, если объект выпадал из области видимости, автоматически вызывалась функция DESTROY(). В Moose для аналогичных задач используется метод DEMOLISH().

Использование new() и DESTROY() в классах на основе Moose — запрещено.

Вызов класса ничем не отличается от вызова стандартного класса perl. Разработчик, использующий ваш класс, вообще не заметит разницы, пока в дело не вступят атрибуты.

Но как бы Moose не пытался выглядеть современным и инновационным, в конечном счете, создание объектов все равно осуществляется старым добрым bless. Пусть и неявно.

Для того, чтобы заставить класс унаследовать что-то от другого класса, можно использовать функцию Moose extends (@superclasses). Данная функция используется вместо привычного use base.

Пример наследования класса

Супер-класс:

Класс-наследник:

Скрипт, использование созданных классов.

Для организации множественного наследования нужно просто указать список классов через запятую.

Для проверки, является ли переменная объектом, можно использовать функцию blessed.

В самом деле, blessed — это функция Scalar::Util::blessed. Используется вместо ref.

 

Что такое атрибут класса в Moose и как его создать

Атрибут является свойством класса, в котором он определен. Атрибут всегда имеет имя и список определяющих характеристик.

Для создания атрибутов в Moose используется функция has. С ее помощью создается атрибут, задается имя и характеристики для него.

Можно передать has список имен, тогда будет создан атрибут под каждым из имен и каждому будут заданы одни и те же параметры.

Список допустимых характеристик атрибутов:

  • is — создает аксессоры для атрибута.
  • clearer — создает метод, который очищает значение атрибута, присваивая ему undef.
  • predicate — создает метод, который возвращает значение true или false, в зависимости от того, установлено значение атрибуту или нет.
  • isa — данная опция задает тип значения атрибута. После указания типа, Moose будет контролировать, чтобы атрибут имел значение только указанного типа.
    Возможные значения: Any, Item, Bool, Undef, Defined, Value, Str, Num, Int, ClassName, RoleName, Ref, ScalarRef, ArrayRef, HashRef, CodeRef, RegexpRef, GlobRef, FileHandle, Object.
  • default — содержит значение атрибута по-умолчанию, которое будет присвоено последнему сразу после его инициализации. Если значение — простой скаляр, то можно прописать его как есть. Если значение — хэш, ссылка и т.п., то придется в качестве обертки использовать sub {}.
  • required — флаг задает необходимость установки значения аттрибута. По умолчанию все аттрибуты необязательны.
  • trigger — задает код, который вызывается на выполнение сразу после того, как было задано значение атрибута. Триггер срабатывает, когда значение задается в рамках конструктора, либо с помощью аксессора. Установка значения по-умолчанию или builder не вызовут срабатывание триггера.
  • builder — содержит название метода, который будет вызываться для получения значения атрибута во время инициализации переменной. Иногда его рекомендуют использовать вместо default.
  • lazy — флаг, может иметь значение 1 или 0. Если задан данный флаг, то установка значения атрибута откладывается на самый последний момент. Полезно, когда значение атрибута зависит от множества разных факторов. Более того, значение атрибута будет вычислено только в том случае, если это потребуется в процессе выполнения программы.
    Если указано это свойство, атрибуту обязательно должно быть назначено значение по-умолчанию или задан builder.

Пример очень простого атрибута

Создаем атрибут:

Используем атрибут в программе:

По сути, атрибут — это всего лишь переменная, типа флага. Альтернатива использованию глобальных переменных.

Пример атрибута, которому назначено значение по умолчанию и определен тип значения:

Использование атрибута подобного типа:

 

Как создать метод в Moose

Создание методов точно такое же, как в стандартном Perl ООП. Любая функция, описанная в классе, будет считаться методом. Пример создания и использования метода в классе:

Использование метода в скрипте:

Для переопределения методов родительского класса, Moose предоставляет функцию override ($name, &sub). В самом деле, ее использование совсем не обязательно, и можно переопределить метод как в стандартном Perl, через sub().

Переопределение метода с помощью override

Супер-класс:

Класс-наследник:

Скрипт, который использует переопределенный метод:

 

Что такое модификаторы методов в Moose и как их использовать

Модификаторы методов в Moose сделаны на основе Class::MOP. Все, что вы знаете о модификаторах Class::MOP, пригодится вам для понимания модификаторов Moose.

Модификатор метода позволяет задать некоторый код, который будет вызываться до, после или во время выполнения функции, к которой он привязан. Немного похоже на идею триггеров в БД. Модификаторы очень удобны. Они могут распарсить и подготовить данные для вызываемой функции, могут сделать запрос к БД, чтобы уточнить наличие информации.

Класс, с методом method() и модификаторами для этого метода:

Использование класса:

После запуска скрипта на консоль будет выведено:

Модификатор метода around

Модификатор around принимает в качестве первого аргумента имя метода, к которому его применили. Далее, программист сам, внутри модификатора должен явно вызвать указанный метод. В результате, получается, что модификатор around выполняет роль обертки для метода.

Класс, который содержит модификатор around:

Использование метода, которому назначен модификатор around:

Модификатор augment и inner

augment — это один из модификаторов методов. before, after — это код, который будет выполнен до или после выполнения метода.

augment задает код, который будет выполнен внутри метода, в том месте, где вызывается inner(). Т.е. augment — полная противоположность модификатора around.

Модификатор может использоваться только в системе с элементами наследования.

На мой взгляд, это настолько страшный для понимания код, что лучше его не использовать.

Что такое роль в Moose и как ее создать

Роль — это новое понятие в perl, вводимое Moose.

Роль — это группа атрибутов, методов и модификаторов методов, которые дополняют использующий роль класс. Одну и ту же роль могут использовать разные классы.

С помощью роли можно задать список методов, которые обязательно должны быть определены в использующем роль классе. Это делает роль похожей на интерфейс.

Можно задать для роли список несовместимых с ней ролей.

Роли не используют наследование.

После того, как роль встроена в класс, это выглядит так, как будто ее атрибуты и методы были заданы непосредственно в классе.

Пример роли:

Для подключения нужной роли используется функция Moose — with (@roles):

Использование класса с подключенными ролями в скрипте:

А теперь второй пример. Попробуем создать роль, которая будет выполнять задачи интерфейса. Т.е. будет только задавать список методов, которые должны быть определены в использующем ее классе.

В стандартном ООП, интерфейс — это класс без полей и без реализации, включающий только заголовки методов. Если некий класс наследует интерфейс, он должен реализовать все входящие в него методы. Интерфейс позволяет быть уверенным, что какой-либо используемый класс реализует все необходимые методы. Данный принцип полезен при разработке продукта большим количеством разработчиков, когда нужно гарантировать совместимость разрабатываемых продуктов.

Официальные конструкции для создания интерфейсов существуют, например, в Java или PHP.

Для задания обязательных методов используется специальная функция requires.

Класс-интерфейс:

Класс, который использует интерфейс:

Если в классе, который использует класс-интерфейс, не будет реализована заданная интерфейсом функция, интерпретатор выдаст длинное и выразительное ругательство.

Использование класса:

 

Вывод ошибок в Moose с помощью confess

confess — в самом деле является функцией Carp::confess . Экспортируется по историческим причинам.

 

Очистка мусора в Moose

Очистка мусора происходит, если в начале класса подключить прагму namespace::autoclean.

 

Ускорение работы классов

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

Метаклассы Moose реализованы так, что можно изменить их в любое время. Добавить методы, атрибуты или удалить их. За подобные удобства приходится расплачиваться производительностью программы.

Для того, чтобы вовремя отреагировать на изменение класса, система вынуждена постоянно рекурсивно обходить классы и отслеживать любые изменения в них. make_immutable — это возможность сказать системе, что вы не собираетесь заниматься динамическим расширением метаклассов, и позволяете ей один раз обработать код, закешировать его и использовать в дальнейшем.

Заключение

Надеюсь, данная статья поможет вам лучше понимать Moose и вполне достаточна для того, чтобы начать с ней работу. Чистая Moose — достаточно компактная система. Для расширения ее возможностей существует много дополнительных модулей — MooseX.

В ближайшее время на блоге будет опубликован фото-отчет о поездке программиста на отдых. Подпишитесь на обновления, чтобы заглянуть в закулисье профессии ;)

Полезные ссылки по теме Moose

search.cpan.org: Moose-2.0604

habr.ru: Moose: ООП в Perl

habr.ru: Moose(X). Продолжение

Объектно-ориентированное программирование в Perl 5

Perl::Moose::Conept

Moose. A Postmodern Object System for Perl

Что такое Moose в Perl. Руководство для начинающих: 2 комментария

  1. Marlik

    Че-то не догнал. В двух словах, зачем он нужен этот фреймворк? Сдается мне, все то-же самое можно использовать в стандартном Perl, создавать пакеты, дергать из них данные, методы…

  2. Natalie Автор записи

    Да, все можно. И Moose совсем не обязателен. Просто некоторые вещи с его помощью делать проще.В основном, интерфейсы — эту возможность я оценила. Реализация интерфейса без Moose вещь более чем творческая и умственно изощренная.

    Все остальные возможности Moose не особенно нужны… до тех пор, пока вы не начнете использовать Catalyst. Catalyst — отличный фреймворк, но при этом — весь пропитан Moose. Не зная Moose, использовать Catalyst на профессиональном уровне будет крайне сложно.

Комментарии запрещены.