Беларусь, рогачёв |
Клипы и ролики. Специальные возможности языка
Свойства и слежение за переменными
Если вам знакомы языки Object Pascal (Delphi) или C#, то вы, наверное, знаете, что такое свойства.
Свойство - это удобная абстрактная надстройка над понятием поля класса с расширяемой семантикой получения значения и присваивания (путем неявного вызова get - и set -методов). Если вы что-нибудь поняли из этого определения, мы снимаем перед вами шляпы и позволяем вам не читать подпараграф "Терминология" (хотя он все равно маленький, так что выиграли вы немного).
Сейчас мы рассмотрим свойства во Флэш МХ вкратце (но все равно нам придется несколько забежать вперед). Более подробно свойства будут рассмотрены в девятой главе.
Терминология: отличие свойства и поля
Если поле - это переменная -член класса, то свойство - это "как бы" поле, а на самом деле - это нечто большее. То есть, обращаетесь вы с ним, как с обычным полем, но при этом вместо непосредственного чтения / записи памяти по определенному адресу происходят вызовы get -метода (при чтении) и set -метода (при записи).
Таким образом:
- упрощается доступ к полю класса (используется интуитивный синтаксис;
- не нарушается инкапсуляция.
Простейшие свойства
Рассмотрим, как объявляются свойства во Flash MX.
Для этого существует специальный метод класса Object - addProperty. Его синтаксис такой:
myObject.addProperty (prop, getFunc, setFunc);
Здесь prop - это имя создаваемого свойства (строка), getFunc - get -метод, setFunc - set -метод. Давайте рассмотрим простой код, создающий свойства:
this.addProperty("scroll", this.getScroll, this.setScroll); this.addProperty("maxscroll", this.getMaxScroll, null);
В этом примере создаются два свойства: scroll (для чтения и записи) и maxscroll (только для чтения). Такой код логично было бы разместить в конструкторе объекта. Впрочем, так делать необязательно - можно в любой момент завести свойства любому объекту. Возникает, правда, вопрос: а нельзя ли завести свойства не одному объекту, а сразу целому классу (в то время, когда мы пишем определение класса)? Можно, и сейчас мы приведем пример того, как это делается (детали этого примера вы поймете позже, когда мы в шестой главе обсудим создание классов во всех подробностях). Предположим, вы только что создали класс TriangleClass. Свойство в него добавляется так:
TriangleClass.prototype.addProperty("area", TriangleClass.prototype.getArea, null); TriangleClass.prototype.addProperty("height", TriangleClass.prototype.getHeight, TriangleClass.prototype.setHeight);
Приведенный код должен быть помещен после определения методов getArea, getHeight и setHeight, причем, желательно, в блоке #initclip, соответствующем определяемому классу (об этом подробнее см. в девятой главе). В данном примере создается два свойства: area (только для чтения) и height (для чтения и записи). Создав объект типа TriangleClass с помощью вызова new TriangleClass(), вы обнаружите в нем эти свойства.
Обратите внимание, несмотря на различия в синтаксисе, результат выполнения обоих примеров одинаков, только в первом примере код, создающий свойства, выполняется при создании каждого объекта, а во втором примере - только при определении класса. И в первом, и во втором примерах get - и set -методам будет передаваться корректная ссылка this, указывающая на объект, через который обратились к свойству.
Слежение за переменными (полями)
Повторим, что при каждом обращении к свойству вызывается либо get -, либо set -метод. Иными словами, если у вас есть свойство, то вы можете проконтролировать любое обращение к нему, например, "довесить" на каждое обращение какой-нибудь специальный код, просто путем внесения изменений в get - и set -методы.
А теперь представьте себе, что вы пользуетесь классом (вами не контролируемым), в котором есть какое-то поле (не свойство, а просто поле), и некоторый код (тоже вами не контролируемый) обращается к этому полю напрямую (да, это нарушает инкапсуляцию, именно поэтому и возникает проблема, о которой мы здесь говорим). Что делать, если вам зачем-то очень нужно контролировать каждое изменение данного поля. Для этого используется слежение за переменными, которое можно организовать, либо используя стандартную функцию watch, либо написав свою собственную. Оба способа мы детально рассмотрим в главе "Классы и клипы " в разделе " Слежение за переменными ".