Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП Perl.docx
Скачиваний:
7
Добавлен:
01.07.2025
Размер:
21 Кб
Скачать
☆

3. Inside-out классы

В предыдущем примере каждому объекту соответствовал свой хэш, благодаря чему пользователь класса мог получить доступ к любому его свойству. Идея «классов наизнанку» заключается в том, чтобы ограничить доступ к свойствам, используя один хэш для всех экземпляров класса.

Пример inside-out класса:

#!/usr/bin/perl

package MyClass; {

use strict;

use Scalar::Util qw/refaddr/;

# $items{refaddr $obj}{name} = value

my %items;

sub new {

my($class, %args) = @_;

# сам объект представляет собой пустой хэш

my $self = bless {}, $class;

my $id = refaddr $self;

$items{$id}{name} = $args{name} || 'Anonymous';

$items{$id}{version} = '1.0';

return $self;

}

sub get_name {

my($self) = @_;

return $items{refaddr $self}{name};

}

sub DESTROY {

my($self) = @_;

# print $items{refaddr $self}{name}." destroyed!\n";

delete $items{refaddr $self};

}

}

1; # ok!

Пример класса-наследника не привожу, потому что там все тривиально. Скрипт, использующий наш класс:

#!/usr/bin/perl

use strict;

use MyClass;

my $anonymous = MyClass->new();

my $alexandr = MyClass->new(

name => "Alexandr"

);

print "anonymous->get_name() = ".$anonymous->get_name()."\n";

print "alexandr->get_name() = ".$alexandr->get_name()."\n";

Программист, который будет использовать класс, не может получить доступ к хэшу %MyClass::items, потому что он объявлен в модуле MyClass как «my», а не «our». Поскольку все свойства класса хранятся в этом хеше, они автоматически становятся закрытыми. При желании мы даже можем объявить закрытые методы.

Однако у этого подхода есть МНОГО недостатков. Во-первых, мы не можем получить protected методы. Впрочем, некоторые программисты заверяют, что при правильном проектировании они не очень то и нужны. Во-вторых, чтобы избежать утечки памяти, мы должны явно освобождать ее в деструкторе. В-третьих, серьезные проблемы возникают в многопоточных приложениях. И, наконец, стандартные средства сериализации не работают с inside-out объектами.

По названным причинам inside-out классы редко объявляются описанным выше образом. Обычно для этого используются специальные CPAN-модули.

4. Модуль Class::InsideOut и иже с ним

Одним из таких модулей является Class::InsideOut. Пример класса, созданного с его помощью:

#!/usr/bin/perl

package MyClass; {

use strict;

use Class::InsideOut qw/:std/;

# для объявления public-свойств

# public ___ => my %____;

# свойство, открытое только для чтения

readonly name => my %name;

# закрытое свойство

private version => my %version;

sub new {

my($class, %args) = @_;

my $self = bless {}, $class;

register($self); # для многопоточности

$name{id $self} = $args{name} || 'Anonymous';

return $self;

}

}

1; # ok!

Пример дочернего класса:

#!/usr/bin/perl

package MyClassChild; {

use base MyClass;

use Class::InsideOut qw/:std/;

use strict;

# опять же, тут никаких protected членов

readonly second_name => my %second_name;

sub new {

my ($class, %args) = @_;

my $self = MyClass::new($class, %args);

$second_name{id $self} = $args{second_name} || 'Noname';

return $self;

}

sub private_test : PRIVATE {

# ...

}

}

1;

Пример скрипта, использующего MyClassChild:

#!/usr/bin/perl

use strict;

use MyClassChild;

use Scalar::Util qw/blessed/;

my $anonymous = MyClassChild->new();

my $alexandr = MyClassChild->new(

name => "Alexandr",

second_name => "Alexeev"

# blog => http://eax.me/

);

print "anonymous->name() = ".$anonymous->name()."\n";

print "alexandr->name() = ".$alexandr->name()."\n";

# пример RTTI в Perl

if(blessed($alexandr) eq "MyClassChild") {

print "alexandr->second_name() = ".

$alexandr->second_name()."\n";

}

Идея та же, что и в предыдущем пункте, только каждому свойству соответствуетотдельный хэш. На этот раз не нужно освобождать память в деструкторе или беспокоиться о многопоточности — Class::InsideOut сделает все за нас.

Из недостатков модуля хотелось бы отметить отсутствие «традиционных» сетеров/геттеров, имена которых начинались бы с set_ и get_, а также нерешенную проблему с сериализацией. В описании модуля сказано, что данный функционал находится в разработке. Учитывая, что модуль последний раз обновлялся в 2008 году, вряд ли мы этого функционала дождемся.

Среди аналогичных CPAN-модулей следует отметить Object::InsideOut иClass::Std. Первый отпугнул меня объемом документации, но выглядит неплохо. Второй поддерживает «правильные» сетеры и гетеры, а также сериализацию, но в нем не реализована поддержка многопоточности.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]