Руководство по actionscript. часть 3, стр. 005

Переменная gameltems класса KidsGame позволяет ему обращаться к игровым данным посредством объекта класса Items. При этом метод newQuestion ( ) класса KidsGame генерирует новый вопрос на основании данных, хранящихся в переменной gameltems. Метод newQuestion ( ) включает основную часть кода, связанного с использованием пространств имен. Именно эта часть интересует нас больше всего, поэтому рассмотрим данный код детально.

Напомним, что каждый вопрос отображает элемент одного из предопределенных наборов элементов, хранящихся в классе Items (fruit: ritemSet или color: ritemSet). Соответственно первая задача, которая стоит перед методом newQuestion ( ), — случайным образом выбрать набор элементов для генерируемого вопроса. Сначала мы получаем весь массив возможных наборов элементов (то есть пространств имен) из класса Items, используя метод gameltems. getltemTypes ( ):

var itemTypes:Array = gameItems. get ItemTypes( );

Затем мы случайным образом выбираем пространство имен из результирующего массива. Для удобства мы присваиваем выбранное пространство имен локальной переменной randomltemType.

var randomltemType:Namespace = itemTypes[Math. floor(

Math. random( )*itemTypes.1ength)];

Обратите внимание, что типом данных переменной randomltemType является тип Namespace, поскольку эта переменная ссылается на значение пространства имен. Как только будет выбран набор элементов (пространство имен) для вопроса, мы должны получить список существующих элементов из этого набора. Чтобы получить соответствующий массив элементов (либо фруктов, либо цветов), мы вызываем метод класса Items, который соответствует нашему выбранному пространству имен, — либо метод fruit: : getltems ( ), либо метод color: : get I terns ( ). Однако вместо того, чтобы обращаться к желаемому методу напрямую, мы динамически генерируем уточненный идентификатор метода, используя переменную randomltemType для определения пространства имен, как показано в следующем коде:

gameltems. randomltemType::get Items( )

Массив, возвращаемый методом, присваивается локальной переменной items: var items:Array = gameltems. randomltemType::get Items( ):

* •»

В предыдущем вызове метода обратите внимание, что поведение программы определяется контекстом программы. Эту особенность можно рассматривать как разновидность полиморфизма, которая основывается не на наследовании классов, а на произвольных группах методов и переменных, определяемых пространствами имен.

Теперь, когда у нас на руках есть массив элементов, мы можем продолжить текущую работу, которая заключается в отображении вопроса на экране. Сначала

мы случайным образом выбираем элемент для отображения из массива элементов:

thisQuestionltem = items[Math. floor(Math. random( )*iterns. length)]:

Затем мы размещаем изображение и варианты ответов для выбранного элемента на экране, используя класс QuestionScreen:

// Удаляем предыдущий вопрос, если он существует if (questionScreen!= null) { removeChild(questionScreen);

}

// Отображаем новый вопрос

questionScreen = new QuestionScreen(this, items. thisQuestionltem): addChild(questionScreen);

Приведем код метода newQuestion ( ) еще раз. Обратите особое внимание на использование значений пространств имен в этом коде, поскольку мы не будем больше возвращаться к нему.

Руководство по actionscript. часть 3, стр. 006

Public function newQuestion ( ):void { // Получаем полный список типов элементов (массив пространств имен) var itemTypes.-Array = gameltems. get ItemTypes ( ); // Случайным образом выбираем тип элемента (одно из пространств имен, // на которые ссылается переменная itemTypes) var randomltemType:Namespace = itemTypes[Math. floor(

Math. random( )*itemTypes.1ength)];

// Получаем элементы набора, выбранного случайным образом var items:Array = gameltems. randomltemType: -.get I terns ( );

// Случайным образом выбираем элемент для данного вопроса // из набора элементов

thisQuestionltem = iterns[Math. floor(Math. random( )*iterns. length)];

// Удаляем предыдущий вопрос, если он существует if (questionScreen!= null) { removeChild(questionScreen);

}

// Отображаем новый вопрос

questionScreen = new QuestionScreen(this, items, thisQuestionltem); addChi1d(questi onScreen);

}

Оставшаяся часть кода из листинга 17.3 относится к игровой логике и созданию пользовательского интерфейса, что в настоящее время не является нашей основной задачей. Как уже отмечалось ранее, вы должны самостоятельно изучить оставшийся код. Информацию о методиках создания пользовательского интерфейса можно найти в части II этой книги.

Что ж, это был хороший практический пример. Впереди нас ждет еще несколько примеров, однако сначала мы должны рассмотреть две фундаментальные концеп-

ции, относящиеся к пространствам имен: открытые пространства имен и пространства имен для модификаторов управления доступом.

Открытые пространства имен и директива use namespace

Помните простой класс Items из листинга 17.1?

package { public class Items { fruit var orange:String = «Round citrus fruit»; color var orange:String = «Color obtained by mixing red and yellow»;

public function Items ( ) { trace(fruit: -.orange); trace(color::orange);

}

}

}

Как уже говорилось, один из способов обращения к переменным orange в предыдущем коде заключается в применении уточненных идентификаторов, как показано ниже:

trace(fruit::orange); // Выводит: Round citrus fruit trace(color::orange); // Выводит: Color obtained by

// mixing red and yellow

Однако язык ActionScript предлагает еще один удобный инструмент для обращения к переменным, уточняемым пространствами имен: директиву use namespace. Директива use namespace добавляет указанное пространство имен в набор так называемых открытых пространств имен для определенной области видимости программы. Открытые пространства имен — это набор пространств имен, к которому обращается компилятор при попытке разрешить неуточненные ссылки. Например, если пространство имен п находится в наборе открытых пространств имен и компилятор встретит неуточненную ссылку на переменную р, то он автоматически проверит существование переменной п: : р.

Руководство по actionscript. часть 3, стр. 007

Рассмотрим общий вид директивы use namespace:

use namespace идентификаторПространстваИмен

Здесь идентификаторПространстваИмен — это идентификатор пространства имен, которое должно быть добавлено в набор открытых пространств имен. Стоит отметить, что данный идентификатор должен быть константой на этапе компиляции, поэтому не может быть переменной, которая ссылается на значение пространства имен.

Посмотрим на примере предыдущего конструктора класса Items, как работает директива use namespace, обратившись напрямую к локальной переменной orange после того, как пространство имен fruit будет добавлено в набор

открытых пространств имен (эта операция также называется открытием пространства имен fruit).

public function Items ( ) { use namespace fruit; trace(orange);

}

Мы добавили пространство имен fruit в набор открытых пространств имей, поэтому, когда компилятор встретит следующий код:

trace(orange);

он автоматически проверит, существует ли уточненный идентификатор fruit: : orange. В нашем примере данный идентификатор существует, поэтому он будет использован вместо локального имени orange. Другими словами, в конструкторе класса Items этот код:

trace(fruit::orange); // Выводит: Round citrus fruit выполняет то же самое, что и следующий: use namespace fruit;

trace(orange); // Выводит: Round citrus fruit

Открытые пространства имен и область видимости

Каждая область видимости в программе на языке ActionScript имеет отдельный список открытых пространств имен. Пространство имен, открытое в определенной области видимости, будет открыто для нее, включая вложенные области, но при этом оно не будет открыто для остальных областей видимости. Открытое пространство имен будет доступно даже до инструкции use namespace (однако лучше всего помещать директиву use namespace в самом верху содержащего ее блока кода).

Напомним, что «область видимости» обозначает «область программы». В ActionScript для d ч каждого пакета, класса и метода определена уникальная область видимости. Условные 4 д]а4 операторы и операторы циклов не имеют собственных областей видимости.

Руководство по actionscript. часть 3, стр. 008

В листинге 17.4 демонстрируется общий код, чтобы показать две различные области видимости со своими отдельными списками открытых пространств имен. Пояснения к коду приводятся в виде комментариев.

Листинг 17.4. Демонстрация открытых пространств имен

public class ScopeDemo { // Создаем пространство имен, private namespace nl = «http://www. example. com/nl»;

// Создаем две переменные, уточняемые пространством имен nl. nl var а:Stri ng = «а»; nl var b:String = «b»;

// Конструктор

public function ScopeDemo ( ) {

// Вызываем метод, который обращается к переменной nl::a. showA( );

}

public function showA ( ):void { // Эта неуточненная ссылка на переменную а полностью соответствует // уточненному идентификатору nl::a, поскольку следующая строка кода // открывает пространство имен nl. trace(a); // OK!

// Открываем пространство имен nl. use namespace nl;

// Неуточненная ссылка на переменную а // снова соответствует уточненному // идентификатору nl::a. trace(a); // ОК!

// Создаем вложенную функцию, function f ( ):void {

// Пространство имен nl остается открытым во вложенных областях

// видимости…

trace(a); // ОК! Соответствует n1::а.

Руководство по actionscript. часть 3, стр. 009

}

// Вызываем вложенную функцию. f( ):

}

public function showB ( ):void { // В следующем коде происходит неправильное обращение к переменной // nl::b. Пространство имен nl открыто только в области видимости метода // showA( ), но не в области видимости метода showB( ), поэтому попытка // обращения окажется неудачной. Более того, в области видимости метода // showB( ) не существует ни одной переменной с простым // идентификатором Ь, поэтому компилятор сгенерирует следующую ошибку: // Attempted access to inaccessible property b through a reference // with static type ScopeDemo.

// (Предпринята попытка обращения к недоступному свойству b через // ссылку на статический тип ScopeDemo.) trace(b); // ОШИБКА!

}

}

Поскольку открытое пространство имен остается открытым во вложенных областях видимости, мы можем открывать пространство имен на уровне класса или пакета с тем, чтобы использовать его в любом месте блока инструкции class или package. Однако стоит отметить, что после того, как пространство имен было открыто, закрыть его будет невозможно. Не существует директивы unuse namespace, равно как не существует способа удалить пространство имен из списка открытых пространств имен определенной области видимости.

Открытие нескольких пространств имен

Вполне допустимо открывать несколько пространств имен в одной и той же области видимости. Например, рассмотрим четыре переменные, относящиеся к двум пространствам имен (переменные взяты из класса Items, представленного в листинге 17.3):

fruit var orange:Item = new Item(«Orange». «fruit-orange. jpg». 1): fruit var apple:Item = new ItemC’Apple». «fruit-apple. jpg». 2): color var orange:Item = new Item(«Orange». «color-orange. jpg». 3); color var purple:Item = new ItemCPurple». «color-purple. jpg». 4):

Предположим, что мы добавили метод showl terns ( ) в класс I terns для отображения всех элементов игры. В этом методе мы можем открыть оба пространства имен fruit и color, азатем обращаться к переменным fruit: : apple и color: : purple, не указывая уточняющее пространство имен:

public function showltems ( ):void { use namespace fruit: use namespace color:

// Вот это да! Никаких пространств имен! trace(apple. name); // Выводит: Apple trace(purple. name); // Выводит: Purple

}

Рассмотрим, как это работает. Как уже известно, термин «открытые пространства имен» означает «набор пространств имен, к которому обращается компилятор при попытке разрешить неуточненные ссылки». Если в указанной области видимости открыто несколько пространств имен, компилятор проверяет каждое пространство абсолютно для всех неуточненных ссылок в данной области видимости. Например, вметоде showltems ( ) открыты оба пространства имен fruit и color. Следовательно, когда компилятор встречает неуточненный идентификатор apple, он проверяет, существуют ли идентификаторы fruit: : apple и color: : apple. В случае с идентификатором apple неуточненная ссылка соответствует идентификатору fruit: : apple, но не соответствует идентификатору color: : apple. Поскольку идентификатор apple соответствует только одному уточненному идентификатору (а именно, fruit: : apple), этот уточненный идентификатор и используется вместо неуточненной ссылки apple.

Руководство по actionscript. часть 3, стр. 010

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

public function showltems ( ):void { use namespace fruit: use namespace color:

// Соответствует fruit::orange и color::orange -// что произойдет в этом случае? trace(orange);

}

Если неуточненная ссылка соответствует имени в более чем одном пространстве имен, возникает ошибка на этапе выполнения. Предыдущий код вызовет следующую ошибку:

Ambiguous reference to orange.

По-русски ошибка будет выглядеть следующим образом: Неоднозначная ссылка на orange.

Из-за ошибки в некоторых компиляторах компании Adobe предыдущая ошибка может остаться незамеченной.

Если открыты оба пространства имен fruit и color, мы должны использовать уточненные идентификаторы fruit: : orange или color: : orange для обращения к нашим переменным orange, исключая неоднозначность, как показано в следующем коде:

public function showltems ( ):void { use namespace fruit; use namespace color;

trace(apple); // Выводит: Apple trace(purple); // Выводит: Purple

// Открыты оба пространства имен fruit и color, поэтому ссылки // на переменную orange должны быть полностью уточнены. trace(fruit::orange); trace(color::orange);

}

Пространства имен для модификаторов управления доступом

Точно так же, как мы используем пространства имен для управления видимостью переменных и методов в наших собственных программах, язык ActionScript использует пространства имен для управления видимостью каждой переменной и каждого метода в любой программе! Помните четыре модификатора управления доступом в ActionScript — public, internal, protected, private? Сам язык ActionScript реализует приведенные правила видимости с помощью пространств имен. Например, с точки зрения ActionScript определение переменной:

class А { private var p:int;

}

означает «создать новую переменную р, уточняемую пространством имен private класса А».

Руководство по actionscript. часть 3, стр. 011

В каждой области видимости ActionScript неявно открывает подходящее пространство имен для различных модификаторов управления доступом. Например, в каждой области видимости всегда добавляется глобальное пространство имен public в набор открытых пространств имен. На верхнем уровне пакета также добавляются пространства имен internal и publ ic данного пакета. В коде класса, который находится внутри пакета, также добавляются пространства имен private и protected данного класса. Таким образом, набор открытых пространств имен включает не

только пространства имен, открытые пользователем, но и пространства имен для управления доступом, которые неявно открываются в каждой области видимости.

Открыть пространства имен для управления доступом явно с помощью директивы use namespace невозможно. Среда выполнения открывает пространства имен для управления доступом автоматически, в соответствии с текущей областью видимости.

Пространства имен для модификаторов управления доступом определяют доступность идентификаторов и предотвращают конфликты именования. Например, в следующем коде суперкласс Parent и подкласс Child определяют переменную с одним и тем же именем, используя модификатор управления доступом private: description. Переменная description класса Parent недоступна для кода в классе Child, поскольку она уточнена пространством имен private класса Parent, которое не открывается в области видимости класса Child. Благодаря этому названия переменных не конфликтуют между собой.

package р { public class Parent. { private var description-.String = «A Parent object»; public function Parent ( ) { trace(description);

}

}

package p { public class Child extends Parent { private var description:String = «A Child object»; public function Child ( ) { trace(description); // Конфликта не происходит

}

}

}

Однако если переменную description класса Parent объявить с использованием модификатора управления доступом protected, возникнет конфликт. Рассмотрим почему. Во-первых, изменим модификатор управления доступом для переменной description на protected:

public class Parent { protected var description-.String = «A Parent object»;

}

Теперь представим себя на месте среды Flash, пытающейся выполнить код в конструкторе класса Child. Мы входим в конструктор и встречаем ссылку на идентификатор description. Чтобы разрешить этот идентификатор, мы должны проверить его существование в открытых пространствах имен. И какие же пространства имен открыты в конструкторе класса Child? Как мы уже знаем, в коде класса, который находится внутри пакета, среда Flash открывает пространства имен private и protected данного класса, пространства имен internal и public пакета и глобальное пространство имен public. Итак, открытыми пространствами имен являются:

? пространство имен private класса Child;

? пространство имен protected класса Child (которое уточняет все члены, унаследованные от непосредственного суперкласса);

? пространство имен internal пакета р;

? пространство имен public пакета р;

? глобальное пространство имен public;

? все пользовательские пространства имен, открытые явным образом.

Руководство по actionscript. часть 3, стр. 012

Когда среда выполнения проверяет существование переменной description в открытых пространствах имен, она находит два соответствия: private : .-description и protected: :description класса Child. Как мы уже знаем из предыдущего раздела, когда неуточненная ссылка соответствует имени в более чем одном пространстве имен, возникает ошибка неоднозначного обращения. Более того, если несколько имен уточняются различными неявно открытыми пространствами имен, возникает ошибка, связанная с конфликтом определений. В случае с переменной description возникнет следующая ошибка:

A conflict exists with inherited definition Parent. description in namespace protected.

На русском языке она будет выглядеть так: Существует конфликт с унаследованным определением Parent. description в пространстве имен protected.

Если в вашем коде существуют конфликтующие имена методов и переменных, компилятор опишет суть конфликта, указав пространство имен, в котором этот конфликт произошел. Например, следующий код:

package { import flash. display.*; public class SomeClass extends Sprite { private var prop:int;

private var prop:int; // Недопустимое повторное определение свойства

}

}

вызовет следующую ошибку:

A conflict exists with definition prop in namespace private.

По-русски это будет звучать так: Существует конфликт с определением prop в пространстве имен private.

На самом деле из-за ошибки компилятора в приложениях Flex Builder 2 и Flash CS3 предыдущее сообщение будет содержать неправильную фразу namespace internal, хотя должно быть namespace private.

Подобным образом, данный код:

package { import flash. display.*; public class SomeClass extends Sprite { private var x;

вызовет следующую ошибку (поскольку — об этом вы можете почитать в справочнике по языку ActionScript компании Adobe — в классе Di splayOb j ect уже определена переменная х с использованием модификатора управления доступом public):

A conflict exists with inherited definition f1 ash. di splay:Di splayObject. x in namespace public.

Руководство по actionscript. часть 3, стр. 013

На русском языке это будет выглядеть следующим образом: Существует конфликт с унаследованным определением flash. display:DisplayObject. x в пространстве имен public.

Директива import открывает пространства имен public. Стоит отметить, что с технической точки зрения импортирование пакета, как показано в следующем коде:

import somePackage.*;

открывает пространство имен public импортированного пакета. Тем не менее оно не открывает пространство имен internal импортированного пакета. Даже если пакет импортируется, его идентификаторы, объявленные с использованием модификатора управления доступом internal, остаются недоступными для внешнего кода.

Практические примеры использования пространств имен

В самом начале этой главы упоминалось четыре практических сценария использования пространств имен:

? предотвращение конфликтов именования;

? управление видимостью членов на уровне прикладной среды;

? управление доступом на основании разрешений;

? реализация различных режимов работы программы.

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

Пример: управление видимостью на уровне прикладной среды

Наш первый пример прикладного использования пространств имен взят из прикладной среды Flex компании Adobe — это библиотека компонентов пользовательского интерфейса и утилит для разработки интернет-приложений с широкими функциональными возможностями.

Прикладная среда Flex включает большое количество кода — сотни классов, размещаемых в дюжинах пакетов. Некоторые методы и переменные этих классов должны быть доступны в различных пакетах, но при этом они должны считаться внутренними по отношению ко всей прикладной среде. Возникает дилемма: если методы и переменные объявить с использованием модификатора управления до-

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

Руководство по actionscript. часть 3, стр. 014

Для разрешения этой ситуации в прикладной среде Flex определяется пространство имен mx internal, используемое для уточнения методов и переменных, которые не должны быть видны за пределами прикладной среды, но при этом должны быть доступны в различных пакетах внутри ее.

Вот объявление пространства имен mx internal:

package mx. core { public namespace mx_internal =

«http://www. adobe. com/2006/f1ex/mx/i nternal»;

}

Рассмотрим конкретный пример использования пространства имен mx internal из прикладной среды Flex.

Для работы с табличными данными наподобие тех, которые используются в программах электронных таблиц, прикладная среда Flex предоставляет компонент DataGr id. Класс DataGrid находится в пакете mx. controls. Вспомогательные классы для компонента Dat aGr id размещаются в отдельном пакете:mx. controls. gridclasses. Чтобы взаимодействие между классом DataGrid и его вспомогательными классами осуществлялось максимально эффективно, DataGrid обращается к некоторым внутренним переменным его вспомогательных классов напрямую, а не с помощью доступных всем методов-получателей. Однако эти внутренние переменные не должны использоваться классами за пределами прикладной среды Flex, поэтому они уточняются пространством имен mx internal. Например, вспомогательный класс mx. controls. gridclasses. DataGridColumn хранит индекс столбца в переменной mx_internal: : colNum.

// Файл DataGridColumn. as mx_internal var colNum:Number;

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

use namespace mx_internal;

а затем обращается к переменной mx internal: : colNum напрямую, как показано в следующем фрагменте кода, взятого из определения метода-писателя:

// Файл DataGrid. as

public function set columns(value:Array):void { // Инициализируем «colNum» для всех столбцов var n:int = value. length; for (var i:int = 0; i < n; i++) {

var column:DataGridColumn = _columns[i];

column. owner = this;

// Обращаемся к переменной mx_internal::colNum напрямую. (Напомним, что

// пространство имен mx_internal открыто, поэтому выражение

// column. colNum эквивалентно выражению column. mx_internal: .colNum.)

column. colNum = i;

}

// Оставшаяся часть метода не приводится

}

Классы за пределами прикладной среды Flex для получения индекса столбца используют общедоступный метод getColumnlndex ( ) вместо обращения к переменной mx_internal: : colNum напрямую.



Полезные ссылки
Случайные записи
  • 01.03.2011">Руководство по actionscript. часть 5, стр. 111
  • 10.06.2011">Подбираю ноутбук для работы и отпуска. Ещё один интересный экземпляр.
  • 09.03.2011">Руководство по actionscript. часть 4, стр. 051
  • 23.08.2011">Пиво не только вредно, но и полезно!
  • 01.03.2011">Руководство по actionscript. часть 5, стр. 130
  • 01.02.2013">Частные уроки вождения
  • 19.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.10
  • 09.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.145
  • 18.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.63
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.97
  • 13.03.2011">Руководство по actionscript. часть 3, стр. 111
  • 23.02.2011">Руководство по actionscript. часть 7, стр. 037
  • 09.03.2011">Руководство по actionscript. часть 4, стр. 055
  • 16.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.34
  • 27.02.2011">Руководство по actionscript. часть 6, стр. 032
Опрос

Какие цвета вы предпочитаете?

View Results

Loading ... Loading ...