Анимация
JavaScript
|
Главная Библионтека 13.9. Создание класса с поддержкой наследования 473 Мы хотим, чтобы поведение inacca Person полностью воспроизводилось в Employee. Создание подобных пустых классов называется «проверкой пустого субкласса»; иначе говоря, мы создаем производный класс, который не делает ничего, кроме наследования от базового. Если базовый класс спроектирован нормально, то производный класс в точности воспроизведет его поведение. Это означает, что при простой замене имени класса все остальное будет работать: use Employee; my $empl = Employee->new(); $empl->name("Jason"); $empl->age(23); printf "%s IS age %d.\n", $empl->name, $empl->age; Под «нормальным проектированием» имеется в виду использование только двухаргументной формы bless, отказ от прямого доступа к данным класса и отсутствие экспортирования. В определенной выше функции Person:: new() мы проявили необходимую осторожность: в конструкторе используются некоторые пакетные данные, но ссылка на них хранится в самом объекте. Другие методы обращаются к пакетным данным через эту ссылку, поэтому проблем быть не должно. Но почему мы сказали функции Person:7iew()i> - разве это не метод? Дело в том, что метод представляет собой функцию, первый аргумент которой определяет имя класса (пакет) или объект (приведенную ссылку). Person:: new - это функция, которая в конечном счете вызывается методами Person->new и Employee->new. Хотя вызов метода очень похож на вызов функции, они все же отличаются. Если вы начнете путать функции с методами, то очень скоро у вас не останется ничего, кроме неработающих программ. Во-первых, функции отличаются от методов фактическими конвенциями вызова - метод вызывается с дополнительным аргументом. Во-вторых, вызовы функций не поддерживают наследования, а методы - поддерживают. Если вы привыкнете к вызовам вида: Вызов метода Вызов функции Person->new() Person::new("Person") Employee->new() Person::new("Employee") Shim = Person: :new(); tt НЕВЕРНО в программе возникнет нетривиальная проблема, поскольку функция не получит ожидаемого аргумента "Person" и не сможет привести его к переданному классу. Еще хуже, если вам захочется вызвать функцию Employee;: new(). Такой функции не существует! Это всего лишь вызов унаследованного метода. Мораль: не вызывайте функции там, где нужно вызывать методы. > Смотри также- perltoot(i),perlobj{l) иperlbot{l); рецепты 13.1; 13.10. 13.10. Вызов переопределенных методов Проблема Конструктор переопределяет конструктор суперкласса. Вы хотите вызвать конструктор суперкласса из своего конструктора. Решение Используйте специальный класс, SUPER: sub meth { my Sself = shift; Sself->SUPER::meth(); Комментарий в таких языках, как С++, где конструкторы не выделяют память, а ограничиваются инициализацией объекта, конструкторы базовых классов вызываются автоматически. В таких языках, как Java и Perl, приходится вызывать их самостоятельно. Для вызова методов конкретного класса используется формулировка $self-> SUPER: ;meth(). Она представляет собой расширение обычной записи с началом поиска в определенном базовом классе и допустима только в переопределенных методах. Сравните несколько вариантов: $self->meth(); # Вызвать первый найденный meth Sself->Where::meth(); # Начать поиск с пакета "Where" $self->SUPER::meth(); « Вызвать переопределенную версию Вероятно, простым пользователям класса; следует ограничиться первым вариантом. Второй вариант возможен, но не реко1цендуется. Последний вариант может вызываться только в переопределенном мето.д«„ Переопределяющий конструктор должен вызвать конструктор своего класса SUPER, в котором выполняется выделение памяти и приведение объекта, и ограничиться инициализацией полей данных. В данном случае код выделения памяти желательно отделять от кода инициализации объекта. Пусть имя начинается с символа подчеркивания - условного обозначения номинально закрытого метода, аналога таблички «Руками не трогать». sub new { my Sclassname = shift; tt Какой класс мы конструируем? my Sself = $classname->SUPER:;new(@ ); $self-> init(@ ); return Sself; tt Вернуть sub inxt { my Sself = shift; $self->{START} = time(); ft Инициализировать поля данных 13.11. Генерация методов доступа с помощью AUTOLOAD 475 $self->{AGE> =0; , $self->{EXTRA} = { @ }1 # Прочее И SUPER: :new и init вызываются со всеми остальными аргументами, что позволяет передавать другие инициализаторы полей: $оЬ] = Widget->new( haircolor => red, freckles => 121 ); Стоит ли сохранять пользовательские параметры в отдельном хэше - решайте сами. Обратите внимание: SUPER работает только для первого переопределенного метода. Если в массиве @ISA перечислено несколько классов, будет обработан только первый. Ручной перебор @ISA возможен, но, вероятно, не оправдывает затраченных усилий. ту Sself = bless {}, Sclass; for my Sclass (@ISA) { my Smeth = Sclass . :: init"; Sself->$meth(@ ) If $class->canC init"); В этом ненадежном фрагменте предполагается, что все суперклассы инициализируют свои объекты не в конструкторе, а в init. Кроме того, предполагается, что объект реализуется через ссылку на хэш. > Смотри также- Класс SUPER рассматривается вperltoot(l) иperlobj(i). 13.11. Генерация методов доступа с помощью AUTOLOAD Проблема Для работы с полями данных объекта нужны методы доступа, а вам не хочется писать повторяющийся код. femeHMe Воспользуйтесь механизмом AUTOLOAD для автоматического построения методов доступа - это позволит обойтись без самостоятельного написания методов при добавлении новых полей данных. Комментарий Механизм AUTOLOAD перехватывает вызовы неопределенных методов. Чтобы ограничиться обращениями к полям данных, мы сохраним список допустимых полей в хэше. Метод AUTOLOAD будет проверять, присутствует ли в хэше запрашиваемое поле. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 [ 152 ] 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |