Анимация
JavaScript
|
Главная Библионтека Программисты на С++ привыкли использовать статические методы, виртуальные методы и методы экземпляров, но Perl поддерживает только методы классов и методы объектов. В действительности в Perl существует только общее понятие «метод». Принадлежцрсть метода к классу или объекту определяется исключительно контекстом использования. Метод класса (со строковым аргументом) можно вызвать для объекта (с аргументом-ссылкой), но вряд ли это приведет к разумному результату. Программисты С++ привыкли к глобальным (то есть существующим на уровне класса) конструкторам и деструкторам. В Perl они идентичны соответственно инициализирующему коду модуля и блоку END{}. С позиций С++ все методы Perl являются виртуальными. По этой причине их аргументы никогда не проверяются на соответствие прототипам функции, как это можно сделать для встроенных и пользовательских функций. Прототипы проверяются компилятором во время компиляции. Функция, вызванная методом, определяется лищь во время выполнения. Философское отступление в своих объектно-ориентированных аспектах Perl предоставляет полную свободу выбора: возможность делать одни и те же вещи несколькими способами (приведение позволяет создать объект из данных любого типа), возможности модификации классов, написанных другими (добавление функций в их пакеты), а также полная возможность превратить отладку программы в сущий ад - если вам этого сильно захочется. В менее гибких языках программирования обычно устанавливаются более жесткие ограничения. Многие языки с фанатичным упорством отстаивают закрытость данных, проверку типов на,стадии компиляции, сложные сигнатуры функций и другие возможности. Все ти возможности отсутствуют в объектах Perl, поскольку они вообще не поддерживаются Perl. Помните об этом, если объектно-ориентированные аспекты Perl покажутся вам странными. Все странности происходят лищь от того, что вы привыкли к философии других языков. Объектно-ориентированная сторона Perl абсолютно разумна - если мыслить категориями Perl. Для любой задачи, которую нельзя решить на Perl по аналогии с Java или С++, найдется прекрасно работающее решение в идеологии Perl. Программист-параноик даже сможет обеспечить полную закрытость: в perltoot{\) рассказано о том, как с помощью приведения замыканий получить объекты, по степени закрытости не уступающие объектам С++ (и даже превосходящие их). Объекты Perl не плохи; просто они другие. > Смотри также- В литературе по объектно-ориентированному программированию Perl упоминается очень редко. Изучение объектно-ориентированных аспектов языка лучше всего начать с документации Perl - особенно с учебника по объектам perltoot(i). За справочной информацией обращайтесь кpethbj(i). Вероятно, этот документ понадобится вам при чтении руководстваperlbot(l), полного объектно-ориентированных фокусов. 13.1. Конструирование объекта Проблема Необходимо предоставить пользователю возможность создания новых объектов, Решение Создайте конструктор. В Perl метод-конструктор не только инициализирует объект, но и предварительно выделяет память для него - как правило, с использованием анонимного хэша. Конструкторы С++, напротив, вызываются после выделения памяти. В объектно-ориентированном мире конструкторы С++ было бы правильнее назвать инициализаторами. Канонический конструктор объекта в Perl выглядит так: sub new { my Sclass = shift; my Sself = {}; bless($self, Sclass); return Sself; Данный фрагмент эквивалентен следующей строке: sub new { bless( { >, shift ) } Комментарий Любой метод, который выделяет память для объекта и инициализирует его, фактически является конструктором. Главное, о чем следует помнить, - ссылка становится объектом лишь после того, как для нее будет вызвана функция bless. Простейший, хотя и не особенно полезный конструктор выглядит так: sub new { bless({ >) > Давайте включим в него инициализацию объекта: sub new { my Sself = { }; # Выделить анонимный хэш bless($self); # Инициализировать два атрибута/поля/переменных экземпляра $self->{START> = timeO; $self->{AGE} = 0; return Sself; > Такой конструктор не очень полезен, поскольку в нем используется одноаргу-ментная форма bless, которая всегда приводит объект в текущий пакет. Это означает, что полезное наследование от него становится невозможным; сконструированные объекты всегда будут приводиться к классу, в котором была откомпилирована функция new. При наследовании этот класс не обязательно совпадет с тем, для которого вызывался данный метод. 13.2. Уничтожение объекта 457 Проблема решается просто-: достаточно организовать в конструкторе обработку первого аргумента. Для метода класса он представляет собой имя пакета. Передайте имя класса функции bless в качестве второго аргумента: sub new { my $classname = shift; tt Какой класс мы конструируем my $self = {>; # Выделить память bless($obref, $classname); tt Привести к нужному типу $self->{START> = time(); # Инициализировать поля данных $self->{AGE> = 0; return $obref; # И вернуть > Теперь конструктор будет правильно наследоваться производными классами. Выделение памяти и приведение можно отделить от инициализации данных экземпляра. В простых классах это не нужно, однако такое разделение упрощает наследование; см. рецепт 13.10. sub new { my Sclassname = shift; # Какой класс мы конструируем my $self = {>; tt Выделить память bless($self, Sclassname); # Привести к нужному типу $self-> init(@ ); tt Вызвать init tt с остальными аргументами return Sself, tt "Закрытый" метод для инициализации полей. Он всегда присваивает START tt текущее время, а AGE - 0. При вызове с аргументами init # интерпретирует их как пары ключ/значение и инициализирует ими объект, sub init { my Sself = shift; Sself->{START> = time(); $self->{AGE} = 0; If (@ ) { my %extra = @ ; @Sself{keys %extra> = values %extra; > 0 Смотри также- perltoot(\) иperlobj(\); рецепты 13.6; 13.9-13.10. 13.2. Уничтожение объекта Проблема Некоторый фрагмент кода должен выполняться в случае, если надобность в объекте отпадает. Например, объект может использоваться в интерфейсе с внешним миром или содержать циклические структуры данных - в этих случаях он 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 |