Анимация
JavaScript


Главная  Библионтека 

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

13.3. Работа с данными экземпляра 461

Программисты, которым приходилось работать с объектами С++, привыкли к тому, что к атрибутам объекта можно обращаться из методов в виде простых переменных. Модуль Alias с CPAN обеспечивает эту и многие другие возможности - например, создание открытых методов, которые могут вызываться объектом, но недоступны для кода за его пределами.

Рассмотрим пример создания класса Person с применением модуля Alias. Обновление «магических» переменных экземпляра автоматически обновляет поля данных в хэше. Удобно, правда?

package Person;

и То же, что и раньше... sub new {

my Sthat = shift;

my Sclass = ref($that) Sthat;

my Sself = {

NAME => undef, AGE => undef, PEERS => [],

bless($self, Sclass); return Sself;

>

use Alias qw(attr);

use vars qw(SNAME SAGE SPEERS);

sub name {

my Sself = attr shift;

if (@ ) { SNAME = shift; >

return SNAME;

>

sub age {

my Sself = attr shift; If (@ ) { SAGE = shift; > return SAGE;

>

sub peers {

my Sself = attr shift; if (@ ) { ©PEERS = @ ; > return @PEERS;

>

sub exclaim {

my Sself = attr shift;

return sprintf "Hi, Im %s, age %d, working with %s", SNAME, SAGE, join(", ", ©PEERS);

>



> Смотри также-

perltoot(i), perlobj(\.) иperlbot{i); документация по модулю Alias с CPAN; рецепты 13.11-13.12.

13.4. Управление данными класса

Проблема

Вам нужен метод, который вызывается для класса в целом, а не для отдельного объекта. Например, он может обрабатывать глобальный атрибут данных, общий для всех экземпляров класса.

Решение

Первым аргументом метода класса является не ссылка, как в методах объектов, а строка, содержащая имя класса. Методы классов работают с данными пакета, а не данными объекта, как показывает приведенный ниже метод population;

package Person; $Body Count = 0;

sub population { return $Body Count >

sub new { # Конструктор

$Body Count++; return bless({}, shift);

>

sub DESTROY { --SBodyCount > # Деструктор

# Позднее пользователь может написать; package main;

for (1..10) { push ©people, Person->new >

printf "There are %d people alive.\n", Person->population();

There are 10 people alive.

sub happy birthday {

my Sself = attr shift; return ++$AGE;

Директива use vars понадобилась из-за того, что Alias играет с пакетными глобальными переменными, имена которых совпадают с именами полей. Чтобы использовать глобальные переменные при действующей директиве use strict, необходимо заранее объявить их. Эти переменные локализуются в блоке, содержащем вызов attr(), словно они объявлены с ключевым словом local. Таким образом, они остаются глобальными пакетными переменными с временными значениями.



13.4. Управление данными класса 463

Комментарий

обычно каждый объект обладает определенным состоянием, полная информация о котором хранится в самом объекте. Значение атрибута данных одного объекта никак не связано со значением этого атрибута в другом экземпляре того же класса. Например, присваивание атрибуту gender объекта her никак не влияет на атрибут gender объекта him, поскольку это разные объекты с разным состоянием:

$him = Person->new(); $him->gender("male");

* $her = Person->new(); $her->gender("female");

Представьте атрибут, общий для всего класса - изменение атрибута для одного экземпляра приводит к его изменению для остальных экземпляров. Подобно тому, как имена глобальных переменных часто записываются с больщой буквы, некоторые программисты предпочитают записывать имя символами верхнего регистра, если метод работает с данными класса, а не с данными экземпляра. Рассмотрим пример использования метода класса с именем Max Bounds:

FixedArray->Max Bounds(100); # Устанавливается для всего класса $alpha = FixedArray->new();

printf "Bound on alpha is %d\n", $alpha->Max Bounds(); 100

Sbeta = FixedArray->new();

$beta->Max Bounds(50); # Также устанавливается для всего класса

printf "Bound on alpha is %d\n", $alpha->Max Bounds();

Реализация выглядит просто:

package FixedArray; SBounds =7; # default sub new { bless( {>, shift ) > sub Max Bounds {

my Sproto = shift;

$Bounds = shift if @ ; # Разрешить обновления

return SBounds;

>

Чтобы фактически сделать атрибут доступным только для чтения, просто удалите команды обновления:

sub Max Bounds { SBounds >

Настоящий параноик сделает SBounds лексической переменной, которая ограничена областью действия файла, содержащего класс. В этом случае никто не сможет обратиться к данным класса через SFixedArray: : Bounds. Работать с данными придется через интерфейсные методы.

Следующий совет поможет вам строить расширяемые классы: храните данные объекта в пространстве имен объекта (в хэще), а данные класса - в пространстве имен класса (пакетные переменные или лексические переменные с файловой об-



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