Руководство по actionscript. часть 2, стр. 143
? Уточняющее пространство имен — пространство имен, внутри которого данное локальное имя является уникальным.
В коде на языке ActionScript уточненные идентификаторы записываются следующим образом:
уточняющееПространствоИмен: :локальноеИмя
Здесь локальное имя и уточняющее пространство имен объединяются вместе с помощью оператора уточнителя имени, записываемого в виде двух двоеточий (: :). Первая часть выражения —уточняющееПространствоИмен — должна быть представлена либо идентификатором пространства имен, либо переменной, значением которой является пространство имен. О том, как присваивать пространства имен переменным, будет рассказано далее, в разд. «Присваивание и передача значений пространств имен». Тем не менее часть уточняющееПространствоИмен не может быть представлена строковым литералом, являющимся названием пространства имен (URI).
Рассмотрим реальный пример использования уточненного идентификатора. Во-первых, вспомните наше предыдущее определение переменной orange, уточненное пространством имен fruit:
fruit var orange:String = «Round citrus fruit»;
Вот как мы обращаемся к этой переменной с помощью уточненного идентификатора:
fruit::orange
Аналогично этому рассмотрим уточненный идентификатор для переменной с локальным именем orange, которое уточнено пространством имен color:
color::orange
Обратите внимание, что в предыдущих примерах локальные имена являются одинаковыми (orange), но отличаются уточняющие их пространства имен. Язык ActionScript использует уточняющее пространство имен для проведения различия между двумя локальными именами. В языке ActionScript уточненные идентификаторы используются точно так же, как и простые; они просто содержат уточняющее пространство имен. Формат уточняющееПространствоИмен: : локальноеИмя применяется одинаково как к именам методов, так и к именам переменных:
someNamespace::р // Обращение к переменной р someNamespace::ш( ) // Вызов метода ш( )
Для обращения к уточненному идентификатору через объект применяется знакомый нам оператор «точка», как показано в следующем коде:
некийОбъект. уточняющееПространствоИмен: -.локальноеИмя
Например, этот код обращается к переменной р объекта someObj, которая уточняется пространством имен someNamespace:
someObj. someNamespace::р
Следующий код вызывает метод m ( ) объекта s omeOb j, который уточняется пространством имен someNamespace:
someObj. someNamespace::m( )
Расширенные имена. Как уже было сказано, уточненный идентификатор является двухкомпонентным именем, состоящим из уточняющего пространства имен и локального имени:
уточняющееПространствоИмен: -.локальноеИмя
Часть уточняющееПространствоИмен в уточненном идентификаторе — это ссылка на объект Namespace, переменная ur i которого определяет название пространства имен.
Руководство по actionscript. часть 2, стр. 144
Для сравнения отметим, что расширенное имя представляет собой двухкомпо-нентное имя, состоящее из литерала названия пространства имен (URI) и локального имени. Расширенные имена используются только в документации — но не в коде — и обычно записываются в следующем виде:
{названиеПространстваИмен}локальноеИмя
Например, снова рассмотрим определение пространства имен fruit:
namespace fruit = «http://www. example. com/games/kidsgame/fruit»;
Теперь рассмотрим определение переменной orange, уточняемой пространством имен fruit:
fruit var orange:String = «Round citrus fruit»;
В коде мы обращаемся к этой переменной с помощью уточненного идентификатора fruit: : orange. Однако в документации мы могли бы обсуждать эту переменную, ссылаясь на действительное название соответствующего пространства имен, а не на ее идентификатор. Это можно сделать с помощью следующего расширенного имени:
{http://www. examplе. com/games/ki dsgame/fruit}orange
В этой книге расширенные имена применяются редко, однако они достаточно распространены в документации по пространствам имен XML. Если вы не используете пространства имен XML, просто знайте, что синтаксис {названиеПростран-стваИмен}локальноеИмя является только соглашением по документированию, но не поддерживаемым вариантом записи кода.
Функциональный пример использования пространств имен
Воспользуемся нашими новыми знаниями о пространствах имен для создания простейшей программы. В листинге 17.1 представлены базовые элементы приложения, которое мы будем разрабатывать на протяжении следующих разделов, — детской игры на распознавание слов. В ней игроку демонстрируется картинка с изображением цвета или фрукта и предлагается выбрать его название из списка вариантов. На рис. 17.1 показаны две различные картинки игры.
Рис. 17.1. Детская игра «Учусь читать»
Пока каждый предмет в игре будет представлен переменной, значением которой является строковое описание. Мы определим набор всех переменных-предметов в классе с именем Items. С помощью пространств имен мы отделим перемен-ные-«фрукты» от переменных-«цветов»; названия переменных-«фруктов» будут уточняться пространством имен fruit, а названия переменных-«цветов» — пространством имен color.
Руководство по actionscript. часть 2, стр. 145
Взглянем на код в листинге 17.1, после чего рассмотрим его более подробно.
Листинг 17.1. Детская игра: функциональный пример использования пространств имен
// Файл fruit. as package {
namespace fruit = «http://www. example. com/games/kidsgame/fruit»;
}
// Файл color. as package {
namespace color = «http://www. example. com/games/kidsgame/color»;
}
// Файл Items. as 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);
}
}
}
Предыдущий код начинается с определения пространств имен нашей игры. Пространство fruit определяется в файле fruit, as, как показано в следующем коде:
package {
namespace fruit = «http://www. example. com/games/kidsgame/fruit»;
}
После этого мы определяем пространство имен color в файле color. as, как показано в следующем коде:
package {
namespace color = «http://www. example. com/games/kidsgame/color»;
}
Оба пространства имен определены на уровне пакета, поэтому обращаться к ним может любой класс нашего приложения.
Руководство по actionscript. часть 2, стр. 146
Затем мы определяем класс Items в файле Items. as. В классе Items определены две переменные, каждая из которых имеет локальное имя orange. Для первой переменной мы указываем уточняющее пространство имен fruit; для второй — уточняющее пространство имен color.
package { public class Items { fruit var orange:String — «Round citrus fruit»; color var orange:String = «Color obtained by mixing red and yellow»;
}
}
Наконец, чтобы убедиться, что наш код работает, в методе-конструкторе класса Items мы используем функцию trace ( ) для отображения значений обеих переменных orange. Чтобы отличать одну переменную orange от другой, используются уточненные идентификаторы fruit: : orange и color: : orange.
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); // Выводит: Round citrus fruit trace(color::orange); // Выводит: Color obtained by // mixing red and yellow
>
}
}
Попробуйте догадаться, что бы произошло, если бы мы изменили предыдущий конструктор класса Items и обращались к простому идентификатору orange, без применения уточняющего пространства имен, как показано в следующем коде:
public function Items ( ) { trace(orange); // Что произойдет здесь?
}
Ответ: возникнет следующая ошибка на этапе компиляции программы:
Access of undefined property orange.
Руководство по actionscript. часть 2, стр. 147
На русском языке она будет звучать так: Обращение к несуществующему свойству orange.
Компилятор не может найти переменную или метод (то есть «свойство») по имени orange, поскольку в области видимости метода-конструктора Items не существует переменной или метода с простым идентификатором orange. Переменные fruit: : orange и color: : orange уточняются с помощью пространств имен, поэтому они оказываются недоступны при попытке обратиться к ним с применением неуточненного идентификатора. И все-таки далее, в разд. «Открытые пространства имен и директива use namespace», мы познакомимся с упрощенным способом обращения к уточненным идентификаторам без использования уточняющего пространства имен.
Очевидно, что в листинге 17.1 не показана полнофункциональная игра, но этот код призван дать вам представление о базовом синтаксисе и использовании пространств имен. Мы завершим создание нашей игры далее в этой главе.
На этом начальном этапе разработки нашей игры вы могли бы поинтересоваться, почему вместо использования пространств имен мы не можем просто определить переменные с длинными именами, например orangeFruit и orangeColor. Или почему нельзя разделить оба вида oranges, присвоив их двум отдельным массивам, как показано в следующем коде:
var fruitList:Array = ["orange", "apple", "banana"]; var colorList:Array = ["orange", "red", "blue"];
Описанные варианты имеют право на жизнь. Фактически, учитывая выбранный уровень упрощений, нам действительно было бы лучше использовать массивы или более длинные имена переменных. Но не стоит пока терять веру в пространства имен; мы собираемся строить системы с более сложными сценариями использования.
Доступность пространств имен
Как и в случае с определениями переменных и методов, определения пространств имен могут быть изменены с помощью модификаторов управления доступом publ i с, internal, protected и private. Местоположение определения пространства имен в сочетании с модификатором управления доступом этого определения указывают, где может быть использован результирующий идентификатор пространства имен.
Вот несколько основных правил, которые помогут решить, где разместить ваши пространства имен.
? Если пространство имен должно быть доступно в любом месте программы или в группе классов, определяйте его на уровне пакета.
? Если вам требуется пространство имен, которое задает видимость переменных и методов внутри одного класса, определяйте его на уровне класса.
? Если пространство имен будет применяться лишь иногда внутри функции и вы знаете идентификатор URI этого пространства имен, но не можете обращаться к нему напрямую, определяйте пространство имен на уровне функции.
Рассмотрим несколько примеров, начав с пространств имен, задаваемых на уровне пакета.
Руководство по actionscript. часть 2, стр. 148
Доступность определений пространств имен на уровне пакета
В следующем коде мы определяем идентификатор пространства имен fruit в пакете kidsgame:
package kidsgame { public namespace fruit = «http://www. example. com/games/kidsgame/fruit»:
}
Поскольку идентификатор fruit объявлен на уровне пакета с использованием модификатора управления доступом publ iс, он может быть применен для уточнения любой переменной или метода в данной программе. Безусловно, код за пределами пакета kidsgame должен импортировать пространство имен fruit перед его использованием, как показано в следующем примере:
package anyPackage { // Импортируем пространство имен fruit import kidsgame. fruit;
public class AnyClass { // Здесь можно применять пространство имен fruit, поскольку оно уже // было импортировано
fruit var banana:String = «Long yellow fruit»;
}
}
Теперь сделаем так, чтобы доступность пространства имен color была ограничена одним пакетом, используя модификатор управления доступом internal:
package kidsgame {
internal namespace color = «http://www. example. com/games/kidsgame/color»;
}
Когда идентификатор пространства имен определяется с применением модификатора управления доступом internal на уровне пакета, он может быть использован только внутри пакета, в котором определен. Это демонстрирует следующий код.
Руководство по actionscript. часть 2, стр. 149
Package kidsgame { public class Items { // Здесь можно применять пространство имен color. Использование // пространства имен color допустимо, поскольку оно происходит внутри // пакета kidsgame
color var green:String = «Color obtained by mixing blue and yellow»;
}
}
package cardgame { import kidsgame. col or; public class CardGame { // Недопустимо.
// Пространство имен color может быть использовано // только внутри пакета kidsgame.
color var purple:String = «Color obtained by mixing blue and red»;
}
}
При определении пространств имен на уровне пакета могут применяться модификаторы управления доступом public и internal, при этом использование модификаторов управления доступом private и protected не допускается. Более того, если в определении пространства имен на уровне пакета модификатор управления доступом опускается, применяется модификатор управления доступом internal. Например, следующий код:
package kidsgame { // internal указывается явно internal namespace fruit;
}
аналогичен данному коду:
package kidsgame { // internal подразумевается неявно namespace fruit;
}
Теперь рассмотрим определения пространств имен на уровне класса.
Руководство по actionscript. часть 2, стр. 150
Доступность определений пространств имен на уровне класса
Идентификатор пространства имен, определенный в классе с использованием модификатора управления доступом private, доступен только внутри данного класса и недоступен в его подклассах и в любом другом внешнем коде:
public class А { private namespace n = «http://www. example. eom/n»; // Отлично. Идентификатор пространства имен п доступен в этом месте, n var someVariable:int;
}
public class В extends A { // Ошибка. Идентификатор пространства имен п недоступен в этом месте, n var someOtherVariable:int;
}
Мы можем использовать пространство имен, объявленное с применением модификатора управления доступом private, для реализации системы управления доступом на основании разрешений. Эта система рассматривается далее, в подразд. «Пример: управление доступом на основании разрешений» разд. «Практические примеры использования пространств имен».
Идентификатор пространства имен, объявленный в классе с использованием модификатора управления доступом protected, internal или public, доступен напрямую в любом месте данного класса и его подклассов, но недоступен в любом другом внешнем коде. Такое определение пространства имен является противоположностью определения на уровне пакета с применением модификатора управления доступом pub lie, создающего идентификатор пространства имен, к которому можно обращаться напрямую из любого места программы. Это демонстрирует следующий код:
public class А { public namespace n = «http://www. example. eom/n»;
// Отлично. Идентификатор пространства имен п доступен напрямую
// в этом месте.
n var someVariable:int;
}
public class В extends A { // Отлично. Идентификатор пространства имен п доступен напрямую // в этом месте, n var someOtherVariable:int;
}
public class С {
// Ошибка. Идентификатор пространства имен п напрямую не доступен // в этом месте.
Руководство по actionscript. часть 2, стр. 151
// (Но идентификатор п мог бы быть доступен, если бы он был определен
// на уровне пакета.)
n var yetAnotherVariable:int;
}
Стоит отметить, что, хотя идентификатор пространства имен, объявленный в классе с использованием модификатора управления доступом internal или public, доступен напрямую только в этом классе и его подклассах, к объекту Namespace, на который ссылается идентификатор пространства имен, можно обратиться с применением синтаксиса обращения к статическим переменным.
Например, чтобы обратиться к объекту Namespace, на который ссылается идентификатор пространства имен п в предыдущем коде, мы могли бы использовать выражение: А. п. Доступ к объектам Namespace с помощью синтаксиса обращения к статическим переменным регламентируется обычными ограничениями, налагаемыми на статические переменные, объявленные с применением модификаторов управления доступом protected, internal и public. В предыдущем коде, поскольку идентификатор п объявлен с использованием модификатора управления доступом public, выражение А. п является допустимым в любом коде, который имеет доступ к классу А. Если бы идентификатор п был объявлен с использованием’ модификатора управления доступом internal, выражение А. п было бы допустимым только внутри пакета, содержащего определение данного пространства имен. Если бы идентификатор п был объявлен с использованием модификатора управления доступом protected, выражение А. п было бы допустимым только внутри класса А и его подклассов.
Однако ссылки на пространства имен, устанавливаемые через класс (например, А. п), не могут быть использованы в качестве атрибута в определении переменной или метода. Следующий синтаксис недопустим, поскольку атрибут определения переменной или метода должен быть константным значением на этапе компиляции:
А. п var p:int; // Недопустимо. А. п не является константой // на этапе компиляции.
Итак, если мы не можем использовать выражение А. п для уточнения определений, для чего оно может использоваться вообще? Оставайтесь с нами, мы скоро узнаем ответ на этот вопрос в разд. «Присваивание и передача значений пространств имен».
Пока рассмотрим последнюю тему, связанную с доступностью пространств имен: определение пространств имен в методах и функциях.
Доступность определений пространств имен на уровне функции
Как и в случае с другими определениями на уровне функции, идентификатор пространства имен, объявленный на уровне функции, не может включать никакие модификаторы управления доступом (то есть он не может быть объявлен с использованием модификаторов управления доступом public, private и т. д.) и доступен только в области видимости данной функции:
public function doSomething ( ):void { // Это недопустимо
private namespace n = «http://www. example. eom/n»;
}
Более тогог определения локальных переменных и вложенных функций не могут использовать пространства имен в качестве атрибутов:
public function doSomething ( ):void { // Это тоже недопустимо namespace n = «http://www. example. eom/n»; n var someLocalVariable:int = 10;
Таким образом, идентификаторы пространств имен, определенные в функции, могут быть использованы только для формирования уточненных идентификаторов (в следующем коде предполагается, что пространство имен п было определено где-то в программе и применяется для уточнения переменной экземпляра someVariable).
Руководство по actionscript. часть 2, стр. 152
Public function doSomething ( ):void { // Это допустимо
namespace n = «http://www. example. eom/n»; trace(n: .-someVariable) ;
}
Определения пространств имен на уровне функции используются только в редких случаях, когда функция не может обратиться к пространству имен, которое временно требуется для этой функции, напрямую, при этом идентификатор URI пространства имен известен. Например, функция, которая обрабатывает фрагмент XML-документа, содержащего уточненные имена элементов, может использовать код, похожий на следующий:
public function getPrice ( ):void { namespace htmlNS = «http://www. w3.org/1999/xhtml»; output. text = htmlNS::table. htmlNS::tr[l].htmlNS::td[l].price;
}
Пространства имен XML будут рассматриваться в гл. 18.
Видимость уточненных идентификаторов
Наверняка вы заметили, что в этой книге определения уточненных идентификаторов не включают модификаторы управления доступом (public, internal, protected или private). Мы видели достаточно много таких определений:
fruit var orange:String = «Round citrus fruit»:
Однако ни одного такого (обратите внимание на присутствие модификатора управления доступом private):
private fruit var orange:String = «Round citrus fruit»;
По понятной причине нельзя использовать модификаторы управления доступом в определениях, которые включают уточняющее пространство имен. Например, следующий код:
private, fruit var orange:String;
вызовет ошибку:
Access specifiers not allowed with namespace attributes
На русском языке она будет звучать так: Использование спецификаторов вместе с атрибутами пространства имен недопустимо.