Архив рубрики «часть 3»

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

Глава 17. Пространства имен

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

}

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

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

}

// Обрабатываем ответ игрока public function submitGuess (guess:int) .-void { traceCGuess: » + guess + «, Correct: » + thisQuestionltem. id); if (guess == thisQuestionltem. id) { questi onScreen. di splayResult(«Correct!»); // Отключить кнопки ответа до тех пор, пока игрок не дождется // следующего вопроса. questionScreen. disable( );

// Подождать 3 секунды перед отображением следующего вопроса, var timer:Timer = new Timer(3000, 1); timer. addEventLi stener(TimerEvent. TIMER, doneResultDelay); timer. start( ); } else {

questionScreen. di spl ayResultC Incorrect. Please try again.»);

}

}

// Создает новый вопрос после того, как был получен // ответ на предыдущий.

private function doneResultDelay (e:TimerEvent):void {

newQuestion( ); } ‘

}

// Файл Item. as package {

// Простой контейнер данных, который хранит информацию об элементе, public class Item {

// Название элемента (например, «apple»)

public var name:String;

// Адрес URL, с которого загружается изображение, // представляющее элемент public var src:String;

// Уникальный идентификатор элемента, который используется // для обработки ответов игрока public var id:int;

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

public function Item (name:String, src:String, id:int) { this. name = name;

this. src = src; this, id = id;

}

}

}

// Файл QuestionScreen. as package {

import flash. events.*;

import flash. display.*;

import flash. text.*;

import flash. net.*;

// Создает пользовательский интерфейс для вопроса public class QuestionScreen extends Sprite {

private var status:TextField;

private var game:KidsGame;

private var items:Array;

private var thisQuestionltem:Item;

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

public function QuestionScreen (game:KidsGame,

items:Array.

Продолжение:

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

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

ThisQuestionltem:Item) { // Сохраняем ссылку на основной объект игры this. game = game;

// Собираем данные о вопросе this. items = items;

this. thisQuestionltem = thisQuestionltem;

// Помещаем вопрос на экран makeQuestion( );

}

// Создаем и отображаем интерфейс для вопроса public function makeQuestion ( ):void {

// Отображаем картинку для элемента

var imgLoader:Loader = new Loader( );

addChild(imgLoader);

imgLoader. load(new URLRequest(thisQuestionltem. src));

// Добавляем набор слов, которые может выбирать игрок,

// щелкая кнопкой мыши. Для упрощения будем отображать

// название каждого элемента в наборе.

var wordButton:WordButton;

for (var i:int = 0; i < items.length; i++) {

wordButton = new WordButton( );

wordButton. setButtonText(i terns[i].name);

wordButton. setID(items[i].id);

wordButton. у = 110 + i*(wordButton. height + 5);

wordButton. addEventLi stener(MouseEvent. CLICK, cli ckLi stener); addChild(wordButton);

}

// Создаем текстовое поле, в котором будет отображаться статус вопроса

status = new TextFieldC );

status. autoSize = TextFieldAutoSize. LEFT;

status. у = wordButton. у + wordButton. height + 10;

status. selectable = false;

addChild(status);

}

// Отображает сообщение в поле статуса public function displayResult (msg:String):void { status. text = msg;

}

// Выводит выбранное пользователем слово для данного вопроса public function disable ( ):void {

// Отключаем события мыши для всех потомков данного объекта Sprite.

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

MouseChildren = false;

}

// Реагируем на событие, вызванное щелчком кнопкой мыши на кнопке-слове

private function clickListener (е:MouseEvent):void { // Выбранный игроком вариант имеет идентификатор элемента, который был // присвоен объекту WordButton в методе makeQuestion( ). game. submitGuess(е. target. get IDC ));

}

}

}

// Файл WordButton. as package {

import flash. text.*;

import flash. display.*;

// Представляет на экране слово, на котором можно щелкнуть кнопкой мыши // (то есть доступный вариант ответа на вопрос). ID обозначает // идентификатор элемента, выбранного игроком (переменная Item. id), public class WordButton extends Sprite {

private var id:int; // Идентификатор элемента, представляемого // данной кнопкой

private var t:TextField;

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

public function WordButton ( ) { t = new TextField( ); t. autoSize = TextFieldAutoSize. LEFT; t. border = true: t. background = true;

t. selectable = false; addChild(t);

buttonMode = true; mouseChildren = false;

}

// Присваивает текст, отображаемый на кнопке public function setButtonText (text:String):void { t. text = text;

}

// Присваивает идентификатор элемента, представляемого данной кнопкой public function setID (newID:int):void { id = newID:

}

// Возвращает идентификатор элемента, представляемого данной кнопкой public function getID ( ):int { return id;

}

}

}

Просмотрели код? Отлично, рассмотрим его более детально. Возможно, вы заметили, что определения пространств имен в игре не изменялись вообще с того момента, как они были представлены в листинге 17.1. Тем не менее существенно изменился класс Items, а также появилось несколько новых классов:

? KidsGame — основной класс приложения;

? I tem — предоставляет информацию о конкретном элементе игры;

? QuestionScreen — формирует пользовательский интерфейс для каждого вопроса;

? WordButton — представляет кнопку-слово на экране.

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

Поскольку сейчас наше внимание сосредоточено на пространствах имен, мы рассмотрим только классы Items и KidsGame. В качестве упражнения рассмотрите оставшиеся классы самостоятельно.

Для начала посмотрим, как изменился класс Items со времени его предыдущего представления в листинге 17.1. Во-первых, мы добавили две новые переменные fruit: : apple и color: : purple, представляющие элементы. Благодаря новым переменным каждая категория элементов для фруктов и цветов теперь состоит из двух элементов: апельсина и яблока для фруктов и оранжевого и фиолетового для цветов. Мы также заменили простые описания элементов из листинга 17.1 (например, Round citrus fruit) экземплярами класса Item. Экземпляры класса Item хранят название элемента, URL-адрес изображения этого элемента и его идентификатор. Следующий код демонстрирует измененные переменные, представляющие элементы. Как и в листинге 17.1, каждая переменная уточняется пространством имен, соответствующим множеству, которому принадлежит данный элемент.

fruit var orange:Item = new Item(«Orange», «fruit-orange. jpg», 1); fruit var apple:Item = new ItemCApple». «fruit-apple. jpg». 2);

color var orange:Item = new Item(«Orange», «color-orange. jpg», 3); color var purple:Item = new ItemC’Purple». «color-purple. jpg», 4);

Кроме того, в класс I terns добавлены два массива, предназначенные для управления элементами в виде групп. Каждый массив содержит полный список элементов своей группы (либо фруктов, либо цветов). Массивы присваиваются переменным с одним и тем же именем (itemSet), но уточняемым различными пространствами имен (fruit и color).

fruit var itemSet:Array = [fruit::orange, fruit::apple]; color var itemSet:Array = [color: :orange, color: .-purple];

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

fruit function getltems ( ):Array { // Возвращает фрукты, return fruit::itemSet. siice(O):

}

color function getltems ( ):Array { // Возвращает цвета, return color::itemSet. slice(0);

}

Наконец, в классе Items определены переменная itemTypes и соответствующий метод-аксессор get ItemTypes ( ). Переменная itemTypes хранит список всех различных множеств элементов в игре. В нашей игре определено только два множества: фрукты и цвета, но в дальнейшем можно будет легко добавить новые множества. Каждое множество элементов соответствует пространству имен, поэтому переменная itemTypes представляет собой массив пространств имен. Метод get ItemTypes ( ) возвращает копию этого массива, предоставляя внешнему коду возможность централизованно получать официальный список типов элементов в игре.

// Переменная itemTypes

private var itemTypes.-Array = [color, fruit]:

// Метод getItemTypes( ) public function getltemTypes ( ):Array { return itemTypes. siice(O);

}

Это все, что касается изменений в классе Items. Теперь рассмотрим новый основной класс приложения KidsGame. В отличие от Items, класс KidsGame никогда не

использует идентификаторы пространств имен fruit и color напрямую. Вместо этого он обращается к указанным пространствам имен через метод экземпляра

getltemTypes ( ) класса Items.

Руководство по 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 класса А».



Полезные ссылки
Случайные записи
  • 12.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.114
  • 16.03.2011">Руководство по actionscript. часть 3, стр. 028
  • 19.03.2011">Руководство по actionscript. часть 2, стр. 095
  • 08.03.2011">Руководство по actionscript. часть 4, стр. 078
  • 19.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.13
  • 14.03.2011">Руководство по actionscript. часть 3, стр. 067
  • 08.03.2011">Руководство по actionscript. часть 4, стр. 088
  • 05.04.2010">Дизайн для вдохновения
  • 04.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.29
  • 01.11.2011">Первые нейросинаптические процессоры
  • 15.03.2011">Руководство по actionscript. часть 3, стр. 052
  • 17.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.125
  • 13.03.2011">Руководство по actionscript. часть 3, стр. 089
  • 05.03.2011">Руководство по actionscript. часть 5, стр. 021
  • 14.03.2011">Руководство по actionscript. часть 3, стр. 070
Опрос

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

View Results

Loading ... Loading ...