|
Добрый день. Я сейчас прохожу курс повышения квалификации - "Профессиональное веб-программирование". Мне нужно получить диплом по этому курсу. Я так полагаю нужно его оплатить чтобы получить диплом о повышении квалификации. Как мне оплатить этот курс?
|
Объектное программирование
Деструктор
В классе может быть описан специальный метод, автоматически вызываемый исполняющей системой при уничтожении каждого объекта. Такой метод называется деструктор (destructor), и он должен иметь зарезервированное имя - DESTROY. Деструктор вызывается при освобождении памяти, занимаемой объектом: это происходит при выходе из блока, где был создан объект, при удалении последней ссылки на объект функцией undef($object) или при окончании программы. Приведем пример шуточного деструктора для класса Person, который при удалении объекта направляет прощание в поток STDERR, называя имя объекта методом say_name():
sub DESTROY {
warn('Прощайте, я ухожу... ' . shift->say_name);
}Деструктор может использоваться, если при окончании работы с объектом нужно выполнить какие-то завершающие действия: например, удалить динамически созданные структуры или сохранить данные объекта в файле. Конструктор в этом случае может считывать сохраненные значения из файла, чтобы присвоить объектам начальные значения.
Способы хранения атрибутов
Анонимные хэши - это самый распространенный, но не единственный способ хранить значения атрибутов объекта. Для этого может применяться массив или даже скалярная переменная, лишь бы при создании объекта в конструкторе это хранилище значений было связано с именем класса функцией bless(). Недостатком этого подхода можно считать то, что ограничение доступа к свойствам достигается лишь на уровне соглашения пользоваться только методами объекта. И поскольку существует возможность изменить значение атрибута напрямую, это может нарушить корректную работу программы. Ведь в методе изменение состояния объекта сопровождается необходимыми проверками, чего не происходит при непосредственном изменении атрибута. Тем более, что в некоторых случаях атрибуты вообще должны быть доступны только для чтения (read-only attribute). Например, при использовании хэша для хранения атрибутов вполне возможно такое некорректное присваивание:
$hobbit->{magic} = 'пёстрая'; # добавлен ошибочный атрибутДля того чтобы надежно обеспечить ограничение доступа к данным, которые хранятся в объекте, применяются замыкания. Чтобы показать, как можно организовать полностью закрытые атрибуты (private attributes) с помощью замыканий, напишем класс Private::Person. В новой версии класса значения атрибутов также хранятся в анонимном хэше, но при создании объекта возвращается ссылка не на него, а на анонимную подпрограмму доступа к данным. Этой функции будет передаваться имя атрибута (и, возможно, новое значение), а она будет возвращать значение атрибута, используя имя атрибута как ключ поиска в анонимном массиве. Это выглядит так:
package Private::Person; # класс "Личность"
sub new { # прототипом может быть
my $invocant = shift; # класс или объект
my $class = ref($invocant) || $invocant;
my $self = { # значения атрибутов:
NAME => '', # имя и
HEIGHT => 0.0 # рост
};
my $closure = sub { # функция доступа к данным
my $field = shift; # по имени атрибута
$self->{$field} = shift if @_; # изменим и
return $self->{$field}; # вернем значение
}; # объектом будет
bless($closure, $class); # ссылка на функцию
}
# метод доступа к атрибуту name
sub name {
my $self = shift; # ссылка на объект-функцию
&{$self}("NAME", @_); # доступ к скрытому значению
}
# метод доступа к атрибуту height
sub height { # то же, что выше, но несколько короче:
&{ $_[0] }("HEIGHT", @_[1 .. $#_ ] )
}
1;Методы доступа к свойствам объектов получают первым аргументом ссылку на функцию доступа к значениям атрибутов и вызывают ее, передавая ей имя поля и остальные свои аргументы. Приведем пример создания объектов нового класса и обращения к их методам. В вызывающей программе все выглядит так, как будто данные по-прежнему хранятся в анонимном массиве:
package main; # вызывающая программа
use Private::Person; # использовать этот класс
my $elf = Private::Person->new; # создать объект и
$elf->name("Леголас"); # задать значения
$elf->height(189); # его атрибутам
# получить доступ к значениям атрибутов объекта
print $elf->name, ' ', $elf->height, ' ';
print ref($elf), "\n"; # тип референта: 'Private::Person'Из примера видно, что имя класса может быть составным, отражая иерархию классов. Поскольку классы - это пакеты, хранящиеся в файле-модуле, то все, что говорилось в предыдущей лекции об именовании модулей, относится и к классам.
Обратите также внимание на то, что конструктор класса Private::Person определен так, что он может вызываться с использованием либо имени класса, либо ссылки на существующий объект. Это проверяется в следующей строке:
my $class = ref($invocant) || $invocant;
Если первым аргументом передана ссылка на объект, то определяется имя его класса, иначе считается, что передано имя класса. Поэтому в программе можно создавать однотипные объекты, обращаясь к методу new() существующего объекта. Например, так:
my $hobbit = Private::Person->new; # вызов с именем класса
$hobbit->name("Bilbo Baggins");
my $frodo = $hobbit->new; # вызов со ссылкой на объект
$frodo->name("Frodo Baggins");