Анимация
JavaScript
|
Главная Библионтека В рецепте 13.1 также рассматриваются функции, возвращающие приведенные ссылки. Конструкторы не обязаны быть методами класса. Также встречаются методы объектов, возвращающие новые объекты (см. рецепт 13.6). Деструктором называется функция, которая выполняется при уничтожении субъекта, соответствующего данному объекту, в процессе сборки мусора. В отличие от конструкторов имена деструкторов жестко фиксируются. Методу-деструктору должно быть присвоено имя DESTROY. Этот метод, если он существует, вызывается для всех объектов непосредственно перед освобождением памяти. Наличие деструктора (см. рецепт 13.2) необязательно. Некоторые языки на уровне синтаксиса позволяют компилятору ограничить доступ к методам класса. В Perl такой возможности нет - программа может вызывать любые методы объекта. Автор класса должен четко документировать открытые методы (те, которые можно использовать). Пользователям icnacca следует избегать недокументированных (то есть неявно закрытых) методов. Perl не различает методы, вызываемые для класса (методы классов), и методы, вызываемые для объекта (методы экземпляров). Если вы хотите, чтобы некоторый метод вызывался только как метод класса, поступите следующим образом: sub class only method { my Sclass = shift, die "class method called on object" if ref Sclass; # Дополнительный код > Чтобы метод вызывался только как метод экземпляра, воспользуйтесь следующим кодом: sub instance only method { my Sself = shift; die "instance method called on class unless ref Sself; # Дополнительный код Если в вашей программе вызывается неопределенный метод объекта, Perl не будет жаловаться на стадии компиляции; вместо этого произойдет исключение во время выполнения. Аналогично, компилятор не перехватывает ситуации, при которой методу, который должен вызываться для простых чисел, передается комплексный аргумент. Метод представляет собой обычный вызов функции, пакет которой определяется во время выполнения. Методы, как и все косвенные функции, не имеют проверки прототипа - проверка выполняется на стадии компиляции. Даже если бы вызовы методов учитывали наличие прототипа, в Perl компилятор не сможет автоматически установить точный тип или интервал аргумента функции. Прототипы Perl предназначены для форсирования контекста аргумента функции, а не для проверки интервала. Странности прототипов Perl описаны в рецепте 10.11. Чтобы предотвратить инициирование исключений для неопределенных методов, можно использовать механизм AUTOLOAD для перехвата вызовов несуществующих методов. Данная возможность рассматривается в рецепте 13.11. Наследование Отношения наследования определяют иерархию классов. При вызове метода, не определенного в классе, поиск метода с указанным именем осуществляется в иерархии. Используется первый найденный метод. Наследование позволяет строить классы «на фундаменте» других классов, чтобы код не приходилось переписывать заново. Классы являются одной из форм многократного использования кода и потому способствуют развитию Лени - главной добродетели программиста. В некоторых языках существует специальный синтаксис наследования. В Perl каждый класс (пакет) может занести список своих суперклассов, то есть родителей в иерархии, в глобальную (не лексическую!) пакетную переменную @ISA. Этот список просматривается во время выполнения программы, при вызове метода, не определенного в классе объекта. Если первый пакет, указанный в @ISA, не содержит искомого метода, но имеет собственный массив @ISA, то Perl перед продолжением поиска рекурсивно просматривает @ISA этого пакета. Если поиск унаследованного метода заканчивается неудачей, проверка выполняется заново, но на этот раз ищется метод с именем AUTOLOAD. Поиск метода $оЬ->meth(), где объект $оЬ принадлежит классу Р, происходит в следующей последовательности: • P.:meth • Любой метод S: :meth() в пакетах S из @P::ISA, рекурсивно. • UNIVERSAL::meth • Подпрограмма Р::AUTOLOAD. • Любой метод S:: AUTOLOAD () в пакетах S из @P::ISA, рекурсивно. • Подпрограмма UNIVERSAL: :AUTOLOAD. В большинстве классов массив @ISA состоит из одного элемента - такая ситуация называется одиночным наследованием. Если массив @ISA содержит несколько элементов, говорят, что класс реализует множественное наследование. Вокруг достоинств и недостатков множественного наследования идут постоянные споры, но Perl поддерживает эту возможность. В рецепте 13.9 рассматриваются основы наследования и базовые принципы построения классов, обеспечивающие удобство субгсяассирования. В рецепте 13.10 мы покажем, как субкласс переопределяет методы своих суперкласов. Perl не поддерживает наследования данных. Класс может напрямую обращаться к данным другого класса, но делать этого не следует. Это не соответствует принципам инкапсуляции и нарушает абстракцию. Если вы последуете рекомендациям из рецептов 13.10 и 13.12, это ограничение не вызовет особых проблем. Косвенный вызов методов Косвенный вызов методов: Slector = new Human::Cannibal; feed Slector "Zak"; move Slector "New York"; представляет собой альтернативный вариант синтаксиса для: Slector = Human::Cannlbal->new(); $obiect->feedC7ak"); $ob]ect->move("New York"); Косвенный вызов методов привлекателен для англоязычных программистов и хорошо знаком программирующим на С++ (где подобным образом используется new). Не поддавайтесь соблазну. Косвенный вызов обладает двумя существенными недостатками. Во-первых, он должен подчиняться тем же ненадежным правилам, что и позиция файлового манипулятора в print и printf; printf STDERR "stuff here\n"; Эта позиция, если она заполняется, должна содержать простое слово, блок или имя скалярной переменной; скалярные выражения недопустимы. Это приводит к невероятно запутанным проблемам, как в двух следующих строках: move $obj->{FIELD}; tt Вероятно, ошибка move Sary[$i]; tt Вероятно, ошибка Как ни странно, эти команды интерпретируются следующим образом: $obj->move->{FIELD}; tt Сюрприз! $ary->move->[Si]; # Сюрприз! вместо ожидаемого: $obj->{FIELD)->move(); tt Ничего подобного $ary[$i]->move; , # Ничего подобного Вторая проблема заключается в том, что во время компиляции Perl приходится гадать, что такое name и move - функции или методы. Обычно Perl угадывает правильно, но в случае ошибки функция будет откомпилирована как метод, и наоборот. Это может привести к появлению невероятно хитрых ошибок, которые очень трудно обнаружить. Формулировке -> Ти раздражающие неоднозначности не присущи, поэтому мы рекомендуем пользоваться только ею. Некоторые замечания по объектной терминологии в объектно-ориентированном мире одни и те же концепции часто описываются разными словами. Если вы программировали на другом объектно-ориентированном языке, возможно, вам захочется узнать, как знакомые термины и концепции представлены в Perl. Например, объекты часто называются экземплярами (instances) классов, а методы этих объектов - методами экземпляров. Поля данных, относящиеся к каждому объекту, часто называются данными экземпляров или атрибутами объектов, а поля данных, общие для всех членов класса, - данными класса, атрибутами класса или статическими переменными класса. Кроме того, термины базовый класс и суперкласс описывают одно и то же понятие (родитель или другой предок в иерархии наследования), тогда как термины производный класс и субкласс описывают противоположное отношение (непосредственный или отдаленный потомок в иерархии наследования). 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 |