Что такое метаклассы в perl? Использование Class::MOP

Что такое метаклассы. Для чего нужны метаклассы. Что такое метаобъектный протокол. Что такое Class::MOP. Для чего используется Class::MOP.

Что такое метаклассы?

В ООП метаклассом является класс, экземплярами которого являются не объекты, как обычно, а классы. Так же, как обычный класс определяет поведение некоторых объектов, метакласс определяет поведение некоторых классов и их экземпляров.

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

Среди самых популярных языков, метаклассы поддерживают: Objective-C, Python, Perl и Ruby.

Иногда идею метаклассов сравнивают с шаблоном проектирования "Фабрика".

Для чего нужны метаклассы?

Идея метаклассов возникает в объектно-ориентированных языках программирования. С ее помощью реализуется завершенный рекурсивный дизайн системы. Удобно при работе с иерархиями классов.

Для Perl в чистом виде, идея метаклассов абсолютно чужеродная. Хотя интересна с точки зрения архитектуры и реализации.

Что такое метаобъектный протокол?

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

Метаобъектный протокол определяет множество функций, которые содержат методы для классов. Программирование на уровне метаобъектного протокола - это определение новых классов вместе с методами для этих классов.

Метаклассы в perl

В чистом Perl 5 такие понятия, как пакет, класс, метод, конструктор не имеют четких различий и границ. Понятие атрибута вообще отсутствует.

Реализация метаклассов в Perl осуществляется с помощью метаобъектного протокола, который представлен системой Class::MOP. Class::MOP и метаклассы широко используются популярным Moose (Официальное определение: "Moose — расширение для Perl 5, позволяющее упростить реализацию ООП". Я не согласна с тем, что Moose что-то там упрощает. На мой взгляд, все совершенно наоборот).

Class::MOP четко разграничивает понятия классов, методов, пакетов, добавляет понятие атрибута. Moose, благодаря Class::MOP, приближает ООП в perl к общепринятым стандартам.

Т.е. по сути, Class::MOP - это больше, чем просто способ создавать метаклассы.

Метаобъектный протокол в perl, Class::MOP

Метаобъектный протокол создает абстрактные понятия классов, методов, объектов, атрибутов. Эти абстракции могут быть использованы для проверки и управления теми элементами системы, которые они описывают.

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

Метаобъектный протокол в perl реализован модулем Class::MOP и включает в себя 4 подпротокола:

  • Class protocol - Средство управления классами. Реализуется через Class::MOP::Class .
  • Attribute protocol - Реализует управление атрибутами классов. Реализуется через Class::MOP::Attribute . Может быть расширен с помощью наследования.
  • Method protocol - Средство для работы с методами объектной системы. Реализуется через Class::MOP::Method .
  • Instance protocol - Обеспечивает некоторый уровень абстракции для создания экземпляров объектов. Реализуется через Class::MOP::Instance

Instance protocol сегодня рассматриваться не будет.

Class protocol

Class::MOP::Class - класс метаобъекта. Данный протокол является самой большой и сложной частью Class::MOP.

Class::MOP::Class является подклассом Class::MOP::Module. Class::MOP::Module, в свою очередь, является подклассом Class::MOP::Package. Package Protocol предоставляет абстракцию для perl-пакетов и методы для работы с пространством имен.

Class::MOP::Class предоставляет множество методов, которые можно разделить по смысловым категориям:

  • создание класса

    Методы этой категории создают объект Class::MOP::Class. Объект Class::MOP::Class является одиночкой и, либо представляет какой-нибудь существующий класс, либо используется для создания класса с нуля.

    Созданный объект будет являться объектом метакласса.

    Если вы попробуете повторно создать объект, то просто получите ссылку на уже созданный экземпляр.

  • информационные методы

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

  • методы для управления наследованием

    Можно получить список всех подклассов, или, наоборот, стать наследником какого-то класса. Методы работают с @ISA.

  • методы для работы с методами класса

    Можно использовать этот тип методов, для создания методов класса, их удаления и изменения. Данные методы в своей работе будут ссылаться на объекты Class::MOP::Method.

  • методы для работы с атрибутами классов

    Методы будут работать с объектами класса Class::MOP::Attribute. Методы используются для задания, поиска, чтения и удаления атрибутов классов.

  • методы для заморозки

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

  • модификаторы метода

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

Пример использования Class::MOP::Class

Расширение функциональности существующего класса

Существующий класс, модуль Meta.pm:

Подключили Class::MOP, затем использовали add_method для создания новых методов класса. Теперь можно использовать класс. Для юзера не будет видно никакой разницы, каким образом были созданы методы.

Создание нового класса

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

Файл модуля, Meta2.pm :

Использование классов, файл meta2.pl:

Результат запуска скрипта meta2.pl:

Работает!

К тому моменту, концепция метаклассов уже стала вполне понятной.

Attribute protocol

Атрибутный протокол - это изобретение Class::MOP. Perl 5 не поддерживает атрибуты. Тем важнее разобраться, что это такое.

Атрибут класса или объекта - это переменная, связанная с классом или объектом. Доступ к атрибутам осуществляется по их имени. Этим атрибуты отличаются от данных, которые содержит объект, и доступ к которым осуществляется только через методы объекта.
У программиста perl закономерно возникает вопрос - нафига это нужно? Ответ: не все пользуются таким классным языком, как perl.

В некоторых объектно-ориентированных языках программирования (например, в Java) не существует глобальных переменных. В этом случае, атрибуты классов являются единственным способом хранения и использования глобальных данных.

Работа с атрибутами в Class::MOP::Class, на мой взгляд, уродлива и не удобна. Вот пример.

Файл модуля Meta4.pm:

Файл скрипта meta4.pl

Вывод после запуска скрипта:

 

Method protocol

Считается, что это это самый простой протокол. Реализован в классе Class::MOP::Method . Класс позволяет создать объект Class::MOP::Method, который содержит информацию о добавляемом методе класса.

В основном, методы объекта Class::MOP::Method просто возвращают техническую информацию. Если заглянуть в исходник Class::MOP::Method, можно увидеть, что документация к модулю занимает места больше, чем код модуля.

Простой пример, в котором я использую методы Class::MOP::Method . Класс Class::MOP::Class создает объект класса, и этот объект является "одиночкой". Чем я и злоупотребила в примере.

Модуль Meta3.pm

Скрипт meta3.pl :

В результате выполнения скрипта meta3.pl, мы получим данные, которые позволят убедиться, что объект класса, действительно, создается в единственном экземпляре:

 

Заключение

На этом закончим. После изучения Class::MOP, я стала лучше понимать принцип работы Moose. Хотя до сих пор не понимаю, в чем ее смысл. Если вам интересно более подробно разобрать концепцию метаклассов, рекомендую почитать документацию по системе Lisp CLOS, которая считается образцовой реализацией метаобъектного протокола.

Подпишитесь на обновления блога, если хотите получить руководство по Moose для начинающих, которое сейчас готовится к публикации.

 

Полезные ссылки

search.cpan.org: Class::MOP::Class

Dynamic data model creation using Class::MOP::Class not working

The Common Lisp Object System MetaObject Protocol

Что такое метаклассы в perl? Использование Class::MOP: 1 комментарий

  1. www2

    На мой взгляд, одна из целей всяких дополнительных реализаций объектных систем в Perl - это получение большего контроля над большой системой. Можно запретить программистам изменять некий аттрибут или допускать хранение в этом аттрибуте только чисел и т.п. Если в процессе работы программы произойдёт попытка сделать недопустимое - об это узнают до того, как проблема проявится где-то позже и более сложным образом.

    Другая цель - это придание программе возможности к саморефлексии. Дать программе возможность получать информацию о каком-то объекте - поддерживается ли определённый метод, какие методы есть, можно ли в них писать и т.п. Это позволяет делать программы более динамичными и гибкими, т.к. благодаря этому становится меньше хардкода. В маленьких программах это может быть не столь важно, потому что программист может удержать в голове все эти знания и при необходимости перепроектировать программу, в больших - приобретает важность.

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