MaxKonovalov38

Современное ООП в Perl

Полное руководство по объектно-ориентированному программированию в Perl с использованием современных практик и модулей.

1. Основы ООП в Perl

1.1 Классы и объекты

package Person;
use strict;
use warnings;

sub new {
    my ($class, %args) = @_;
    my $self = {
        name => $args{name} // 'Unknown',
        age  => $args{age}  // 0,
    };
    return bless $self, $class;
}

sub name {
    my ($self) = @_;
    return $self->{name};
}

sub age {
    my ($self) = @_;
    return $self->{age};
}

1;

Базовый класс Person с конструктором и методами доступа.

1.2 Наследование

package Employee;
use strict;
use warnings;

use parent 'Person';

sub new {
    my ($class, %args) = @_;
    my $self = $class->SUPER::new(%args);
    $self->{salary} = $args{salary} // 0;
    return $self;
}

sub salary {
    my ($self) = @_;
    return $self->{salary};
}

Класс Employee, наследующий от Person и добавляющий свойство salary.

2. Современные практики

2.1 Использование Moose

package User;
use strict;
use warnings;

use Moose;

has 'username' => (
    is       => 'ro',
    isa      => 'Str',
    required => 1,
);

has 'email' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
);

has 'password' => (
    is       => 'rw',
    isa      => 'Str',
    required => 1,
    trigger   => sub {
        my ($self, $new) = @_;
        $self->_hash_password($new);
    },
);

sub _hash_password {
    my ($self, $password) = @_;
    # Хеширование пароля
    $self->{password} = sha256_hex($password);
}

__PACKAGE__->meta->make_immutable;

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

2.2 Роли (Traits)

package Role::Loggable;
use strict;
use warnings;

use Moose::Role;

has 'logger' => (
    is      => 'ro',
    isa     => 'Logger',
    handles => {
        'log_info'  => 'info',
        'log_error' => 'error',
    },
);

sub log_action {
    my ($self, $action) = @_;
    $self->log_info("Action performed: $action");
}

Роль Loggable, добавляющая функциональность логирования.

3. Продвинутые возможности

3.1 Метапрограммирование

package Meta::Class;
use strict;
use warnings;

use Moose;

sub add_method {
    my ($class, $name, $code) = @_;
    $class->meta->add_method($name, $code);
}

sub add_attribute {
    my ($class, $name, %spec) = @_;
    $class->meta->add_attribute($name, %spec);
}

__PACKAGE__->meta->make_immutable;

Пример метапрограммирования с использованием Moose.

3.2 Декораторы

package Decorator::Cache;
use strict;
use warnings;

use Moose;

has 'cache' => (
    is      => 'ro',
    isa     => 'HashRef',
    default => sub { {} },
);

sub decorate {
    my ($self, $method) = @_;
    return sub {
        my ($object, @args) = @_;
        my $key = join(':', $method, join(',', @args));
        return $self->{cache}{$key} if exists $self->{cache}{$key};
        $self->{cache}{$key} = $object->$method(@args);
    };
}

Декоратор для кэширования результатов методов.

4. Тестирование ООП кода

4.1 Модульные тесты

use strict;
use warnings;

use Test::More;
use Test::Moose;

use Person;

my $person = Person->new(name => 'John', age => 30);

does_ok($person, 'Person', 'Объект является экземпляром Person');
is($person->name, 'John', 'Имя установлено корректно');
is($person->age, 30, 'Возраст установлен корректно');

done_testing();

Тестирование класса Person с использованием Test::More и Test::Moose.

4.2 Тестирование ролей

use strict;
use warnings;

use Test::More;
use Test::Moose;

use Role::Loggable;

my $role = Role::Loggable->meta;

does_ok($role, 'Moose::Role', 'Role::Loggable является ролью');
has_attribute_ok($role, 'logger', 'Роль имеет атрибут logger');
can_ok($role, 'log_action', 'Роль имеет метод log_action');

done_testing();

Тестирование роли Loggable с использованием Test::Moose.

5. Лучшие практики

5.1 Иммутабельные объекты

package Immutable::Point;
use strict;
use warnings;

use Moose;

has 'x' => (
    is       => 'ro',
    isa      => 'Int',
    required => 1,
);

has 'y' => (
    is       => 'ro',
    isa      => 'Int',
    required => 1,
);

sub move {
    my ($self, $dx, $dy) = @_;
    return Immutable::Point->new(
        x => $self->x + $dx,
        y => $self->y + $dy,
    );
}

__PACKAGE__->meta->make_immutable;

Пример иммутабельного класса с использованием Moose.

5.2 Композиция вместо наследования

package Logger;
use strict;
use warnings;

use Moose;

sub info {
    my ($self, $message) = @_;
    print "[INFO] $message\n";
}

__PACKAGE__->meta->make_immutable;

package Service;
use strict;
use warnings;
use Moose;

has 'logger' => (
    is      => 'ro',
    isa     => 'Logger',
    handles => ['info'],
    required => 1,
);

sub process {
    my ($self, $data) = @_;
    $self->info("Processing data: $data");
    # Обработка данных
}

__PACKAGE__->meta->make_immutable;

Пример использования композиции вместо наследования.

Это руководство охватывает основные аспекты современного ООП в Perl, включая: