Использование MooseX::Singleton в Catalyst-приложении на конкретном примере, при реализации работы с конфигурационными данными. Использование паттерна "Singleton" в Catalyst-приложении. Примеры кода. Примеры использования Class::Accessor.
Синтаксис:
1 2 3 4 |
package MyClass; use MooseX::Singleton; has config => ( is => 'rw' ); |
1 2 3 4 5 6 7 8 9 |
package main; use MyClass; my $instance = MyClass->instance; # можно вызвать MyClass->instance еще раз, будет возвращена ссылка # на тот же самый объект. my $same = MyClass->instance; |
Пример использования MooseX::Singleton
Задача:
В catalyst-приложении планируется использование внешнего конфигурационного файла. Требуется,
чтобы файл был прочитан только один раз, и в дальнейшем, все модули приложения имели дело с одним
объектом. Для этого:
- Создаем класс Config, который осуществляет получение конфигурационных данных, их обработку.
- Создаем класс SingletonConfig, который реализует идеи паттерна Singleton и позволяет создать
объект-одиночку. - Передаем данные конфига Catalyst-приложению.
Config.pm
Config.pm реализует доступ к конфигурационным данным. В приведенном примере, конфиг - это всего лишь хеш. Можно определить содержимое хеша так, как сделано в примере, а можно - взять данные из файла, распарсить и уже потом поместить их в хеш.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package Config; use base qw/Class::Accessor/; __PACKAGE__->mk_accessors(qw/config_data/); sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{'config_data'} = { 'dbhost' => 'localhost' }; return $self; } 1; |
Что такое Class::Accessor
Class::Accessor используется для автоматического создания функция-аксессоров. Аксессоры (от англ. access — доступ) - это функции, которые реализуют доступ к внутренним данным объекта.
Т.е. вместо того, чтобы писать для каждого поля объекта код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
sub name { my $self = shift; my $value = shift; if($value) { $self->{name} = $value; } return $self->{name}; } sub city { ... } |
Можно использовать Class::Accessor и создать функции-аксессоры одной строкой:
1 |
__PACKAGE__->mk_accessors(qw/name city/); |
- Метод mk_accessors() позволяет создать аксессор и для записи данных в поле объекта, и для чтения данных из него.
- Чтобы создать аксессор только для чтения данных (getter), можно использовать метод mk_ro_accessors() .
- Для создания аксессоров, которые позволяют только записывать данные, но не получать их (setter), можно использовать метод mk_wo_accessors() .
В дальнейшем, созданный аксессор можно использовать:
1 2 3 4 5 6 |
my $my_obj = MyClass->new({ 'name' => 'value1' }); my $info = $my_obj->name; $my_obj->name('value2'); |
Вызов SUPER::new позволяет использовать унаследованный у Class::Accessor метод new(), чтобы создать объект собственного класса.
1 |
my $self = $class->SUPER::new(@_); |
SingletonConfig.pm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package SingletonConfig; use MooseX::Singleton; use Config; has config => ( is => 'rw' ); sub BUILD { my $self = shift; my $conf_obj = Config->new(); my $config_data = $conf_obj->config_data; $self->config($config_data); $self; } 1; |
MyApp.pm
1 2 3 4 5 6 7 8 |
package MyApp; use Moose; use SingletonConfig; __PACKAGE__->config( %{ SingletonConfig->instance->config }, ); |
Метод instance() - специальная альтернатива методу new() - либо создает новый объект, либо возвращает ссылку на уже существующий.
$c->config (в данном случае __PACKAGE__->config) - возвращает или получает ссылку на хеш, который содержит конфигурационные данные для Catalyst-приложения.
MyApp::Controller::Root
После этого, можно получать доступ к конфигурационным данным из любого модуля.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package MyApp::Controller::Root; use uni::perl ':dumper'; use Moose; use namespace::autoclean; BEGIN { extends 'Catalyst::Controller' } sub index :Path :Args(0) { my ( $self, $c ) = @_; $c->stash->{dbhost} = $c->config->{'dbhost'}; } 1; |