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

Интерфейсы-маркеры

Чтобы быть полезными, интерфейсы могут вообще не содержать никаких методов. Иногда пустые интерфейсы, называемые интерфейсами-маркерами, применяются для «отметки» (обозначения) класса, обладающего некоторой возможностью. Требования, предъявляемые к отмеченным классам (классам, реализующим интерфейс-маркер), описываются в документации по каждому конкретному интерфейсу-маркеру. Например, API среды выполнения Flash включает интерфейс-маркер IBitmapDrawable, обозначающий класс, который может быть отображен объектом BitmapData. Класс BitmapData будет отображать только те классы, которые реализуют интерфейс IBitmapDrawable (хотя на самом деле этот интерфейс не определяет никаких методов). Интерфейс IBitmapDrawable используется просто для того, чтобы «показать», что данный класс пригоден для работы с растровым изображением. Вот исходный код интерфейса IBitmapDrawable:

package flash. display { interface IBitmapDrawable { }

}

Другой пример использования составных типов

Как уже известно из предыдущего примера с протоколирующим классом, класс может не только наследоваться от другого класса, но и реализовывать интерфейс. Экземпляры подкласса одновременно принадлежат типу данных суперкласса и типу данных интерфейса. Например, экземпляры класса LogUI из рассмотренного примера принадлежали типам данных Sprite и LogRecipient, поскольку класс LogUI был унаследован от класса Sprite и реализовывал интерфейс LogRecipient. Рассмотрим эту важную архитектурную структуру на новом примере.

**4

Для понимания материала, изложенного в этом разделе, требуется предварительное знание массивов (упорядоченных списков значений), которые еще не рассматривались Эа1 в этой книге. Если вы незнакомы с массивами, то пока пропустите этот раздел и вернитесь к нему после изучения гл. 11.

Предположим, мы создаем приложение, которое сохраняет объекты на сервере с помощью серверного сценария. Класс каждого сохраняемого объекта обязан предоставить метод serialize ( ), возвращающий строковое представление экземпляров данного класса. Строковое представление используется для воссоздания определенного объекта с нуля.

Одним из классов нашего приложения является простой класс Rectangle с переменными экземпляра width, height, fillColor и lineColor. Для представления объектов Rectangle в виде строк класс Rectangle реализует метод serialize( ), который возвращает строку следующего формата:

«wi <№\=значение | hei ф^значение | f i 11 col ог=значение \ 1 i necol ог=значение"

Чтобы сохранить объект Rectangle на сервере, мы вызываем метод serialize ( ) над данным объектом и передаем полученную строку в наш серверный сценарий. В дальнейшем мы сможем получить эту строку и создать новый экземпляр класса Rectangle, размеры и цвет которого будут соответствовать значениям исходного экземпляра.

Для упрощения данного примера мы будем полагать, что каждый сохраняемый объект в приложении должен сохранять только имена переменных и их значения. Мы также будем полагать, что никакие значения переменных сами по себе не являются объектами, для которых требуется сериализация (то есть преобразован в строку).

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

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

1. Соберет объекты для сохранения.

2. Преобразует каждый объект в строку (вызвав метод serialize( )).

3. Перенесет объекты на диск.

Чтобы гарантировать тот факт, что каждый сохраняемый объект может быть се-риализован, класс StorageManager отклонит любые экземпляры классов, которые не принадлежат типу данных Serializable. Вот фрагмент кода класса StorageManager, демонстрирующий метод addOb j ееt ( ), который используется объектами для регистрации в списке сохраняемых объектов (обратите внимание, что в этот метод могут быть переданы только экземпляры, принадлежащие типу Serializable):

package { public class StorageManager { public function addObject (o:Serializable):void { }

}

}

Тип данных Serializable описывается одноименным интерфейсом, который содержит один-единственный метод serialize ( ), как показано в следующем коде:

package { public interface Serializable { function serialize( ) .-String;

}

}

Для выполнения сериализации создадим класс Serialize г, реализующий интерфейс Serializable. Этот класс предоставляет следующие базовые методы для сериализации любого объекта:

? setSerializationObj ( )— указывает объект для сериализации;

? setSerializationVars ( ) — задает, какие переменные объекта должны быть сериализованы;

? setRecordSeparator ( ) — указывает строку, используемую в качестве разделителя между переменными;

? serialize( ) — возвращает строку, представляющую объект.

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

Рассмотрим исходный код класса Serializer: package {

public class Serializer implements Serializable { private var serializationVars:Array; private var serializationObj:Serializable; private var recordSeparator:String;

public function Serializer ( ) { setSeri alizati onObj(thi s);

}

public function setSerializationVars (vars:Array):void { serializationVars = vars;

}

public function setSerializationObj (obj:Serializable):void { serializationObj = obj;

}

public function setRecordSeparator (rs:String):void { recordSeparator = rs;

}

public function serialize ( ):String { var s:String = «»;

// Обратите внимание, что счетчик цикла // уменьшается до нуля.

// а его обновление (декремент i) происходит внутри // условного выражения цикла

for (var i:int = serializationVars. length; —i >= 0; ) { s += serializationVars[i]

+ «=» + String(serializationObj[serializationVars[i]]); if (i > 0) { s += recordSeparator;

}

}

return s; } ‘

}

}

Если какой-либо класс желает воспользоваться возможностями сериализации класса Serializer, то может просто расширить его. Класс, непосредственно расширивший класс Serializer, унаследует и интерфейс Serializable, и реализацию этого интерфейса классом Serializer.

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

Обратите внимание на общую структуру системы сериализации: класс Serializer реализует интерфейс Serializable, предоставляя базовую реализацию, которая может быть использована в других классах через процедуру наследования. Но при этом классы могут реализовать интерфейс Serializable самостоятельно, предоставив желаемое поведение для метода serialize ( ).

Например, следующий код демонстрирует класс Point, определяющий переменные х и у, которые должны быть сериализованы. Этот класс расширяет класс Serializer и непосредственно использует его возможности.

package {

public class Point extends Serializer { public var x:Number; public var y:Number;

public function Point (x:Number. y:Number) { super( );

setRecordSeparator(«.»); setSerializationVars(["x". "y"]);

this. x = x; this. у = у;

}

}

}

Код, желающий сохранить экземпляр класса Point на диск, просто вызывает метод serialize ( ) над этим экземпляром, как показано в следующем примере:

var p:Point = new Point(5. 6);

trace(p. serialize( )); // Отображает: y=6,x=5

Стоит отметить, что класс Point непосредственно не реализует интерфейс Serializable. Этот класс расширяет класс Serializer, который, в свою очередь, реализует интерфейс Serializable.

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

Класс Point не расширяет никакой другой класс, поэтому он может свободно расширить класс Serializer. Тем не менее, если некий класс желает использовать класс Serializer, но уже расширяет другой класс, вместо наследования необходимо применять композицию. Иными словами, вместо расширения класса Serializer класс непосредственно реализует интерфейс Serializable, сохранит объект Serializer в переменной экземпляра и переадресует вызовы метода serializer ( ) этому объекту. Например, рассмотрим код упомянутого ранее класса Rectangle. Этот класс расширяет класс Shape, но использует возможности класса Serializer через композицию (обратите особое внимание на строки, выделенные полужирным шрифтом):

// Суперкласс Shape package { public class Shape {

public var fillColonuint = OxFFFFFF;

public var lineColor:uint = 0;

public function Shape (fillColonuint. lineColor:uint) { this. fillColor = fi11 Col or: this. lineColor = lineColor;

}

// Класс Rectangle package {

// Подкласс Rectangle непосредственно реализует // интерфейс Serializable

public class Rectangle extends Shape implements Serializable { public var width:Number = 0; public var height:Number = 0; private var serializer:Serializer:

public function Rectangle (fil 1 Col or :uint. lineColonuint) { super(fillColor, lineColor)

// Именно здесь создается композиция

serializer = new Serializer( );

seri ali zer. setRecordSeparator(«|»);

seri alizer. setSeri alizationVars(["height", "width",

"fillColor". "lineColor"]); seri ali zer. setSeri ali zati onObj(this);

}

public function setSize (w:Number. h:Number):void { width = w; height = h:

}

public function getArea ( ):Number { return width * height;

}

public function serialize ( ):String { // Здесь класс Rectangle переадресует вызов метода serialize( ) // экземпляру класса Serializer, сохраненному // в переменной serializer

return serializer. serialize( );

}

}

}

Как и в случае с классом Point, код, желающий сохранить экземпляр класса Rectangle, просто вызывает метод serialize ( ) над этим объектом. Вызов метода через композицию будет переадресован экземпляру класса Serializer, сохраненному в классе Rectangle. Вот пример использования этого класса:

var r:Rectangle = new Rectangle(0xFF0000. OxOOOOFF); r. setSizedO. 15);

// Отображает: 1ineColor=2551fi11 Color=167116801width=101height=15 trace(r. serialize( ));

Если класс желает реализовать собственную версию метода serialize ( ) вместо того, чтобы использовать базовую версию этого метода, предоставляемую классом Serializer, он должен непосредственно реализовать интерфейс Serializable, предоставив определение и само тело метода serialize( ).

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

Разделение интерфейса типа данных Serializable и его реализации позволяет любому классу легко выбрать один из следующих вариантов реализации метода

serialize ( ):

? расширить класс Serializer;

? использовать класс Serializer через композицию;

? непосредственно предоставить собственную реализацию метода serialize( ).

Если класс не расширяет другой класс, он может расширить класс Serializer (этот вариант наименее трудоемкий). Если класс уже расширяет другой класс, он может использовать возможности класса Serializer через композицию (этот вариант наиболее гибкий). Наконец, если класс нуждается в собственной уникальной процедуре сериализации, он может непосредственно реализовать интерфейс Serializable (этот вариант наиболее трудоемкий, но в некоторых ситуациях обойтись без него невозможно).

Принимая во внимание гибкость описанной структуры, корпорация Sun Microsystems рекомендует, чтобы в приложениях на языке Java любой класс, у которого могут быть подклассы, являлся реализацией некоего интерфейса. По существу, подклассы могут создаваться непосредственно от данного класса или же он может использоваться классом, унаследованным от другого класса, через композицию. Рекомендация корпорации Sun также имеет смысл и для больших приложений, разрабатываемых на языке ActionScript.

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

НекийАбстрактныйТип

Абстрактное описание типа данных

Реализует

j»"»"! Интерфейс I | Класс

Реализует

НекийКонкретныйТип

Реализация типа данных

Расширяет

Сохраняет

НекийКонкретныйПодтип

НекийАбстрактныйТип

используется через наследование

НекийДругойТип

Несвязанный класс

Т

Расширяет

)

НекийДругойПодтип

НекийАбстрактныйТип используется через композицию

Экземпляр НекийКонкретныйТип

Рис. 9.1. Множественное наследование типов данных через интерфейсы

На рис. 9.2 показана структура конкретных классов Serializable, Point и Rectangle из предыдущего примера.

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

Serializable

Абстрактное

описание типа данных

—Г»

Реализует

Интерфейс I I Класс

Реализует

Serializer

Реализация типа данных

1 г

Расширяет Сохраняет

Point

Serializer используется через наследование

Shape

Несвязанный класс

Расширяет

Rectangle

Serializer используется через композицию

>Экземпляр Serializer

Рис. 9.2. Множественное наследование типов данных на примере интерфейса Serializable

Впереди еще много важного

Познакомившись с классами, объектами, наследованием, типами данных и интерфейсами, мы завершили изучение базовых концепций объектно-ориентированного программирования. До конца части I мы рассмотрим еще несколько других фундаментальных тем, касающихся языка ActionScript. Однако изученные концепции объектно-ориентированного программирования не останутся невостребованными, поскольку они являются основой языка ActionScript.

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

В следующей главе рассматриваются инструкции и операторы языка ActionScript.

ГЛАВАМ

Инструкции и операторы

В этой главе приводится краткое, организованное в виде справочника, описание инструкций и операторов языка ActionScript, со многими из которых вы уже встречались в данной книге. Вместо того чтобы рассматривать каждую инструкцию и оператор по отдельности, эта книга обучает использованию инструкций и операторов в контексте других тем по программированию. Таким образом, глава содержит множество перекрестных ссылок на соответствующие разделы и примеры, разбросанные по всей книге. Информацию по операторам, которые не рассматриваются в данной книге, можно найти в справочнике по языку ActionScript корпорации Adobe.

Инструкции

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

В табл. 10.1 перечислены инструкции языка ActionScript, их синтаксис и назначение.

Таблица 10.1. Инструкции языка ActionScript

Инструкция Использование Описание

break break Завершает цикл или инструкцию switch. Подробную информацию можно найти в гл. 2

case case выражение: вложенные_инструкции Обозначает инструкцию, выполняемую по условию в инструкции switch. Подробную информацию можно найти в гл. 2

continue continue; Пропускает оставшиеся инструкции в текущем цикле и начинает новую итерацию с начала цикла. За дополнительной информацией обратитесь к документации от корпорации Adobe

default default: вложен н ые_и нстру кци и Обозначает инструкцию (-и), выполняемую (-ые) инструкцией switch, когда результат условного выражения не соответствует ни одному из значений выражений case. Дополнительную информацию можно найти в гл. 2

do-while do{ вл ожен н ые_и нстру кци и } while (выражение) Разновидность цикла while, гарантирующая, что тело цикла будет выполнено по крайней мере один раз. Дополнительную информацию можно найти в гл. 2

for for (инициализация; условноеВыражение; корректирование) { инструкции } Многократно выполняет блок инструкций (цикл for). Синоним цикла while, однако выражения инициализации и корректирования цикла размещаются вместе с условным выражением в верхней части цикла. Дополнительную информацию можно найти в гл. 2

Таблица 10.1 (продолжение)

Инструкция Использование Описание

for-in for (переменная in объект) { инструкции } Перечисляет имена динамических переменных экземпляра или элементы массива. Дополнительную информацию можно найти в гл. 15

for-each-in for each (переменная-ИлиЗначениеЭлемента in объект) { инструкции } Перечисляет значения динамических переменных экземпляра или элементы массива. Дополнительную информацию можно найти в гл. 15

if-else if-else if (выражение) { вложен ные_и нстру кци и } else if (выражение) { вложенные_инструкции } else { вложен н ые_и нстру кци и } Выполняет одну или несколько инструкций в зависимости от условия или ряда условий. Дополнительную информацию можно найти в гл. 2

label label: инструкция label: инструкции Связывает инструкцию с идентификатором. Применяется вместе с инструкциями break или continue. За дополнительной информацией обратитесь к документации от корпорации Adobe

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

super super(apryMeHTl, аргу-мент2… аргументп) super. метод(аргумент1, аргумент2… аргументп) Вызывает метод конструктора суперкласса или перекрытый метод экземпляра. Дополнительную информацию можно найти в гл. 6

switch switch (выражение) { вложенные инструкции } Выполняет указанный код в зависимости от условия или ряда условий (является альтернативой инструкции if-else if-else). Дополнительную информацию можно найти в гл. 2

throw throw выражение Генерирует исключение (ошибку) на этапе выполнения. Дополнительную информацию можно найти в гл. 13

try/catch/ finally try { // код, который может // сгенерировать // исключение } catch (еггопТипОшиб-КИ1){ // Код обработчика // ошибки типа // Тип0шибки1 } catch (еггопТипОшиб-ки1Ч){ // Код обработчика // ошибки типа // Тип0шибки1М } finally { // Код, который // выполняется всегда } Окружает блок кода для реакции на возможные исключения, возникающие на этапе выполнения. Дополнительную информацию можно найти в гл. 13

Инструкция Использование Описание

while while (выражение) { вложенные_инструкции } Многократно выполняет блок инструкций (цикл while). Дополнительную информацию можно найти в гл. 2

with with (объект) { вложенные инструкции } Выполняет блок инструкций в контексте данного объекта. Дополнительную информацию можно найти в гл. 16

Операторы

Оператор — это символ или ключевое слово, предназначенные для управления, объединения или преобразования данных. Например, следующий код использует оператор умножения (*), чтобы умножить число 5 на число 6:

5 * 6;

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

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

Операторы выполняют действия над указанными значениями данных (операндами). Например, в операции 5*6 числа 5 и 6 являются операндами оператора умножения (*).

Отдельные операции могут быть объединены в одно сложное выражение. Например:

((width * height) — (Math. PI * radius * radius)) / 2

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

var radius:int = 10; var height:int = 25;

var circleArea:Number = (Math. PI * radius * radius); var cylinderVolume:Number = circleArea * height;

Количество операндов

Операторы иногда классифицируют по количеству принимаемых операндов (то есть требуемых для выполнения операции). Некоторые операторы языка ActionScript принимают один операнд, некоторые — два, а один оператор принимает даже три операнда:

-х // Один операнд

х * у // Два операнда

(х == у) ? «true result» : «false result» // Три операнда

Операторы, принимающие один операнд, называются унарными’, операторы, принимающие два операнда, называются бинарными’, операторы, принимающие три операнда, называются тернарными. Для наших целей мы будем рассматривать операторы с точки зрения выполняемых ими действий, а не с точки зрения количества принимаемых операндов.

Приоритет операторов

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

4 + 5*6 // Возвращает 34, поскольку 4 + 30 = 34

Выражение 4 + 5*6 вычисляется, как «4 плюс произведение 5 и 6», поскольку оператор * имеет более высокий приоритет, чем оператор +.

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

Подобным образом, если в одном выражении встречаются оператор «меньше чем» (<) и оператор конкатенации (+), операция конкатенации будет выполнена первой. предположим, мы хотим сравнить две строки и отобразить результат сравнения при отладке программы. не зная приоритетов операторов < и +, мы можем по ошибке использовать следующий код:

traceCresult: » + «а» < "b");

Из-за приоритетов операторов < и + код выдаст значение f al se, хотя мы ожидали увидеть несколько иной результат:

result: true

Чтобы определить результат выражения «result: » + «а» < "ь", среда flash сначала выполнит операцию конкатенации (поскольку оператор + обладает более высоким приоритетом, чем <). результатом конкатенации строки "result: " со строкой " а " является новая строка "result: а ". после этого среда выполнения flash сравнивает полученную строку со строкой "ь" и получает значение false, поскольку первый символ строки "result: а" находится дальше по алфавиту, чем символ "ь".

Если вы сомневаетесь в приоритетах используемых операторов или хотите указать другую последовательность выполнения операций, используйте круглые скобки, которые обладают самым высоким приоритетом:

«result: » + («а» < "b") // возвращает: "result: true"

(4 + 5) * 6 // Возвращает 54, поскольку 9 * 6 = 54

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

х > У || У == z // х больше у или у равняется z

может оказаться сложным для восприятия без знания таблицы приоритетов. Оно становится гораздо более понятным, когда расставлены круглые скобки:

(х > у) || (у == z) // Гораздо лучше!

Ассоциативность операторов

Как уже известно, приоритет операторов определяет очередность их выполнения в выражении: операторы, обладающие более высоким приоритетом, выполняются раньше операторов с более низким приоритетом. Однако что произойдет, если в одном выражении встретятся несколько операторов с одинаковым уровнем приоритета? В данном случае применяются правила ассоциативности операторов, определяющих направление операции. Операторы могут обладать либо левой (выполняются слева направо), либо правой ассоциативностью (выполняются справа налево). Например, рассмотрим следующее выражение:

b * с / d

Операторы * и / обладают левой ассоциативностью, поэтому операция умножения слева (Ь * с) выполняется первой. Предыдущий пример эквивалентен следующему выражению:

(Ь * с) / d

Здесь оператор = (оператор присваивания) обладает правой ассоциативностью, поэтому выражение

а = b = с = d

читается, как «присвоить значение d переменной с, затем присвоить значение с переменной Ь, после чего присвоить значение b переменной а», как показано в следующем примере:

а = (Ь = (с = d))

Унарные операторы обладают правой ассоциативностью; бинарные операторы обладают левой ассоциативностью, за исключением операторов присваивания, обладающих правой ассоциативностью. Условный оператор ( ? :) также обладает правой ассоциативностью. Ассоциативность операторов достаточно понятна на интуитивном уровне, но если сложное выражение вернуло неожидаемое значение, воспользуйтесь дополнительными круглыми скобками, чтобы указать желаемый порядок выполнения операций. Более подробную информацию по ассоциативности операторов в языке ActionScript можно найти в документации от корпорации Adobe.



Полезные ссылки
Случайные записи
  • 14.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.64
  • 16.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.33
  • 18.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.102
  • 02.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.108
  • 09.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.138
  • 02.03.2011">Руководство по actionscript. часть 5, стр. 086
  • 17.06.2012">«Лаборатория Касперского» отметила сокращение количества спама
  • 22.07.2011">Acer Aspire One 532g
  • 02.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.121
  • 23.02.2011">Руководство по actionscript. часть 7, стр. 038
  • 16.03.2011">Руководство по actionscript. часть 3, стр. 011
  • 15.02.2014">Как установить розетку?
  • 19.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.15
  • 13.03.2011">Руководство по actionscript. часть 3, стр. 091
  • 17.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.124
Опрос

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

View Results

Loading ... Loading ...