Типы не ограничены определениями класса. Типы также могут принимать
форму интерфейсов. Интерфейсы определяют, какие свойства и методы
доступны типу.
Термин «интерфейс» сам по себе описывает
актуальный набор доступных (обычно публичных) свойств и методов,
имеющихся в распоряжении объекта. Это тот же набор свойств и методов,
который вы видите при просмотре определений класса в справке, или
ссылке на язык ActionScript. Это общий термин, используемый практически
во всех языках программирования. var myObj:Object = new Object();
myObj.foo = "foo";
myObj.bar = function():String {
return this.foo;
}
Интерфейс обозначенного выше объекта состоит из свойства foo и метода bar.
Язык
ActionScript также поддерживает определения интерфейсов. Определения
интерфейсов похожи на определения классов (обычно начинающиеся с
заглавной буквы "I"), они описывают, какие свойства и методы имеет
объект, но не идут так далеко, чтобы предоставить реализацию для них
(которая остается работой класса). Когда класс внедряет интерфейс,
необходимо, чтобы он поддерживал реализацию свойств и методов внутри
внедренного интерфейса, либо явно, либо через механизм наследования.
Основная
идея, которая кроется за интерфейсами, заключается в том, чтобы иметь
больше разновидностей типов. Подобно классам, интерфейсы также являются
типами. Цель типа, после всего прочего, заключается в описании
интерфейса объекта так, чтобы флеш смог распознать, когда вы
используете типизированное значение корректно. Вам будет выдана ошибка,
когда вы попытаетесь получить доступ к части интерфейса объекта,
который не описан в его типе, несмотря на то, что был ли этот тип
определен типом класса, или типом интерфейса. Поэтому, почему бы просто
не использовать типы класса? В языке
ActionScript существуют некоторые ситуации, где определенное свойство
может содержать более одного вида экземпляров, но требует, чтобы каждый
из них имел один и тот же интерфейс (как в свойствах и методах), даже
если они являются экземплярами неродственных классов. Примером этого
является ситуация с методом BitmapData.draw(). Подпись или определение
для draw() начинается так, как показано далее:
public function draw(source:IBitmapDrawable, matrix:Matrix = null, …
Обратите внимание, что первый параметр имеет тип
IBitmapDrawable. IBitmapDrawable – это интерфейс, описывающий объекты,
которые могут использоваться с методом draw(). Классы, реализующие этот
интерфейс - это BitmapData и DisplayObject, поэтому только экземпляры
этих классов (или их подклассов), имеющие тип IBitmapDrawable, могут
использоваться с методом draw(). Лучшим
примером может служить интерфейс IEventDispatcher. Этот интерфейс, в
отличие от IBitmapDrawable, на самом деле определяет методы, связанные
с самим интерфейсом. Эти методы включают:
addEventListener dispatchEvent hasEventListener removeEventListener willTrigger
Класс
EventDispatcher, реализующий этот интерфейс, требуется для определения
и предоставления реализации каждого из этих методов, и он это делает.
Любой другой класс, который так же реализует интерфейс
IEventDispatcher, тоже будет вынужден проделывать эти же вещи. В
настоящее время не существует других родных для флеш классов,
реализующих IEventDispatcher, кроме класса EventDispatcher, хотя
некоторые Flex классы (AbstractService и DataService) делают это.
Причина,
по которой класс EventDispatcher имеет собственный интерфейс,
заключается в том, что функционал класса EventDispatcher может быть
использован в классах двумя способами. Один из них – расширение класса
EventDispatcher или подкласса EventDispatcher (так что его методы
наследуются), или использование экземпляра EventDispatcher в качестве
свойства класса, чтобы через него добавлять операции событий (это
называется композицией). Если по какой-либо причине класс не может
расширить EventDispatcher (например, если вместо этого ему требуется
расширить Proxy), то для управления событиями ему понадобиться
экземпляр EventDispatcher. В этом случае будет невозможно распознать
класс EventDispatcher как тип, даже если некоторый функционал будет в
нем присутствовать. Вместо этого классу потребуется реализовать
интерфейс IEventDispatcher, так чтобы значения, ожидающие интерфейс
класса EventDispatcher, могли получить тип IEventDispatcher и
продолжали работать с экземпляром этого класса.
// any object extending EventDispatcher or
// using EventDispatcher with composition
var dispatcher:IEventDispatcher;
Если
вам когда-либо потребуется переменная с типом EventDispatcher, то вам
всегда надо будет использовать вместо этого интерфейс IEventDispatcher.
Он охватит все экземпляры, наследующие от EventDispatcher, а также те,
которые используют композицию для получения функционала класса
EventDispatcher.
Вы также можете решить
создать свои собственные определения интерфейсов, которые можно будет
использовать для описания пользовательского типа пользовательских
классов.
|