Привет! Я не совсем понял постановки зададачи, но думаю тебя интересует следующее.
| Код | package MyClass;
# Коструктор sub new { my $ch = shift; my $class = ref( $ch ) || $ch; my $self = [ qw(ONE TWO THREE) ]; return bless($self, $class); }
# метод добавляет один елемент в конец массива sub setElement { my $self = shift; push( @{$self}, shift ); }
# Метод извлекает первый елемент массива sub getElement { my $self = shift; return @{$self} ? shift @{$self} : undef; }
1;
|
$self = это и есть наш массив екземпляра, точнее ссылка на массив.
Теперь о my и our. Раз уж речь пошла о закрытости в классах, то давай и рассмотрим пример с классом. Для примера, давай создадим класс и тестовый файл, который будет использовать наш класс: Файл: MyClass.pm
| Код | package MyClass;
my @private_array = qw(ONE TWO THREE); our @public_array = qw(A B C D);
# конструктор sub new { my $ch = shift; my $class = ref($ch) || $ch; my $self = {}; return bless($self, $class); }
# Метод возвращает массив @private_array sub getPrivateArray { return @private_array; }
# Метод добавляет новый элемент в конец массива sub pushLast { push(@private_array, $_[1]); }
# Метод добавляет новый елемент в начало массива sub pushFirst { unshift(@private_array, $_[1]); }
# Метод возвращает длину массива sub getLength { return scalar @private_array; }
# Метод возвращает размер массива в байтах sub getSize { my $size = 0; $size += length( $_ ) for @private_array; return $size; }
1;
|
Файл: test.pl
| Код | #!/usr/bin/perl -w use strict; # Ищем модули и классы в текущем каталоге use lib qw(.); # Подключаем класс use MyClass;
# Создаём объект my $cls = new MyClass();
# Получаем массив и выводим его в STDOUT print join(", ", $cls->getPrivateArray()), "\n";
# Посмотрим размер массива print "Now in array " . $cls->getLength() . " elements (" . $cls->getSize() . " bytes)\n";
# Просто разделитель print "=" x 60, "\n";
# Добавляем новый элемент в конец массива $cls->pushLast("FOUR");
# Получаем массив и выводим его в STDOUT print join(", ", $cls->getPrivateArray()), "\n";
# Посмотрим размер массива print "Now in array " . $cls->getLength() . " elements (" . $cls->getSize() . " bytes)\n";
# Просто разделитель print "=" x 60, "\n";
# Добавляем новый элемент в начало массива $cls->pushFirst("ZERO");
# Опять выводим массив print join(", ", $cls->getPrivateArray()), "\n";
# Посмотрим размер массива print "Now in array " . $cls->getLength() . " elements (" . $cls->getSize() . " bytes)\n";
# Просто разделитель print "=" x 60, "\n";
# Пробуем обратиться к массиву напрямую, а не через методы доступа # Работать не будет, так как переменные объявленные как my, имеют # лексическую область видимости. Для теста раскоментируй следующую строку # print "Close array: " . join(", ", @MyClass::private_array) . "\n";
# Попробуем теперь таким же способом вывести открытый массив, объявленный как our print "Open array: " . join(", ", @MyClass::public_array) . "\n";
|
Здесь стоит обратить внимание на то, что массив @private_array имеет лексическую область видимости, т.е. к нему имеют доступ все методы которые находятся с ним в одном пакете. Если нужна ещё более сильная закрытость, то можно захватить в блок, массив и методы для работы с ним. Тогда доступ к нему будут иметь только те методы, которые находятся вместе с ним в одном блоке ( в одной лексической области видимости ). Для примера попробуем немного изменить код класса MyClass. Сохрани следующий класс и тестовый файл в одном каталоге: Файл: MyClass2.pm
| Код | package MyClass2;
our @public_array = qw(A B C D);
# конструктор sub new { my $ch = shift; my $class = ref($ch) || $ch; my $self = {}; return bless($self, $class); }
########################################################### { # Начинается блок, т.е. новая лексическая область видимости # Всё, что объявлено здесь как my не видно за пределами # этой области.
# Наш массив my @private_array = qw(ONE TWO THREE);
# Метод возвращает массив @private_array, этот метод видит наш, закрытый, массив. sub getPrivateArray { return @private_array; }
# Метод возвращает длину массива, этот метод видит наш, закрытый, массив sub getLength { return scalar @private_array; }
# Метод возвращает размер массива в байтах, этот метод тоже видит наш, закрытый, массив sub getSize { my $size = 0; $size += length( $_ ) for @private_array; return $size; } } # Закончился блок. Всё, что находится за пределами этого блока, не имеет # доступа к тому, что объявлено внутри блока как my. ###########################################################
# Метод добавляет новый элемент в конец массива, этот метод не имеет доступа к # массиву @private_array sub pushLast { if ( @private_array ) { # добавим в конец закрытый массив новый элемент push(@private_array, $_[1]); } else { # в противном случае добавим этот элемент в конец открытого массива push(@public_array, $_[1]); } }
# Метод добавляет новый элемент в начало массива, этот метод не имеет доступа к # массиву @private_array sub pushFirst { if ( @private_array ) { # Добавим в начало массива @private_arraу новый елемент unshift(@private_array, $_[1]); } else { # в противном случае добавим этот элемент в начало открытого массива unshift(@public_array, $_[1]); } }
1;
|
Файл: test2.pl
| Код | #!/usr/bin/perl -w use strict; # Ищем модули и классы в текущем каталоге use lib qw(.); # Подключаем класс use MyClass2;
# Создаём объект my $cls = new MyClass2();
# Получаем массив и выводим его в STDOUT print join(", ", $cls->getPrivateArray()), "\n";
# Посмотрим размер массива print "Now in array " . $cls->getLength() . " elements (" . $cls->getSize() . " bytes)\n";
# Просто разделитель print "=" x 60, "\n";
# Добавляем новый элемент в конец массива $cls->pushLast("FOUR");
# Получаем массив и выводим его в STDOUT print join(", ", $cls->getPrivateArray()), "\n";
# Посмотрим размер массива print "Now in array " . $cls->getLength() . " elements (" . $cls->getSize() . " bytes)\n";
# Просто разделитель print "=" x 60, "\n";
# Добавляем новый элемент в начало массива $cls->pushFirst("ZERO");
# Опять выводим массив print join(", ", $cls->getPrivateArray()), "\n";
# Посмотрим размер массива print "Now in array " . $cls->getLength() . " elements (" . $cls->getSize() . " bytes)\n";
# Просто разделитель print "=" x 60, "\n";
# Пробуем обратиться к массиву напрямую, а не через методы доступа # Работать не будет, так как переменные объявленные как my, имеют # лексическую область видимости. Для теста раскоментируй следующую строку # print "Close array: " . join(", ", @MyClass2::private_array) . "\n";
# Попробуем теперь таким же способом вывести открытый массив, объявленный как our print "Open array: " . join(", ", @MyClass2::public_array) . "\n";
|
Заметь, что все элементы, были добавлены в открытый массив, а не в закрытый. Теперь к закрытому массиву имеют доступ только 3 метода getPrivateArray(), getLength() и getSize(). Если вынести массив из блока, на старое место, то новые элементы будут добавлены в закрытый массив, а не в открытый. Те методы, которые находятся внутри блока, в нашем случае это getPrivateArray(), getLength() и getSize(), имеют доступ как к отрытому массиву, так и к закрытому. Просто в нашем случае они этого не делают, не потому, что не получится, а потому, что не было нужды. Для эксперимента, добавь в блок, в классе MyClass2.pm, ещё два метода:
| Код | # Метод возвращает общее кол-во элементов в обоих массивах sub getTotalLength { return @public_array + @private_array; }
# Метод возвращает общий размер в байтах, обоих массивов sub getTotalSize { my $size = 0; $size += length($_) for (@public_array, @private_array); return $size; }
|
А в тестовую программу test2.pl добавь, в конец следующие строки:
| Код | # Просто разделитель print "=" x 60, "\n";
# Покажем общее кол-во элементов обоих массивов и их размер в байтах print "Total elements = " . $cls->getTotalLength() . " (" . $cls->getTotalSize() . " bytes)\n";
|
На самом деле, добавление новых методов в лексическую область, было излишним. Можно было бы вынести их за пределы лексической области и сделать так, что бы они были более универсальны. Давай попробуем сделать это. Вынеси теперь последние 2 метода (getTotalLength() и getTotalSize()), за пределы блока, сохранись и попробуй запустить тестовый файл. Результат будет будет не верным, точнее он будет показывать нам лишь размер массива @public_array. Для того, что бы всё это заработало вне лексической области видимости массива, воспользуемся уже существующими методами доступа. Теперь давай поправим наши, последние, два метода (getTotalLength() и getTotalSize()), следующим образом:
| Код | # Метод возвращает общее кол-во елементов в обоих массивах sub getTotalLength { my $self = shift; # Получаем кол-во элементов массива @private_array, через метод доступа, # определённый ранее в той же лексической области, что и массив @private_array return @public_array + $self->getLength(); }
# Метод возвращает общий размер в байтах, обоих массивов sub getTotalSize { my $self = shift; my $size = 0; # Узнаём размер массива @public_array $size += length($_) for (@public_array); # Узнаём размер массива @private_array, через метод доступа, который определили # ранее в той же лексической области, что и массив @privete_array и возвратим общее # кол-во байт return $size + $self->getSize(); }
|
Теперь мы получим правильное значение, не зависимо от того, расположены они (методы) в одной лексической области с массивом @private_array или вне этой области.
Но учти, что такой массив не является членом экземпляра, все изменения которые ты будешь делать, будут отражаться и на других объектах этого класса, т.е. если изначально создать два объекта, после вносить какие либо изменения через один объект, а в конце вывести общее кол-во елементов через оба объекта, то результаты будут одинаковы. Если тебе нужно, что бы каждый объект хранил свои идивидуальные члены то тебе нужен первый способ, который я привёл вначеле. Этот же способ более подходит для создания так называемых приватных методов. Т.е. ты объявляешь переменную, как my, а присваиваешь ей ссылку на подпрограмму.
| Код | my $private_method = sub { # тело метода }
|
Как ты уже наверное догадался, мы получим закрытый метод, который нельзя вызвать из вне пакета, а точнее той лексической области видимости, к которой он относится. Его так же можно захватить в блок, причём глубина блоков может быть любой.
Что касается символа подчёркивания _, в начале имени метода, то это лишь соглашение, что такой метод считается закрытым и его вызывать из вне не нужно.
Вот что пишет Ларри Уолл о закрытости, в книге "Программирование на Perl":
| Цитата | Perl не требует, что бы вы придерживались какого-то определённого стиля программирования, и не одержим идеей закрытости, как некоторые другие объектно-ориентированные языки программирования. Однако Perl одержим идеей свободы, и одна из свобод, которые Perl предоставляет программисту, это право избрать такую меру закрытости, какую он пожелает. На самом деле, Perl может обеспечить более сильную закрытость в своих классах и объектах, чем C++. Это означает, что Perl ни в чём не ограничивает программиста и, в частности, не ограничивает его право ограничивать самого себя (если вас занимают такого рода вещи).
|
|