Статьи

AS3 101: быстрый совет — когда использовать статические свойства и методы

«Статические» свойства и методы принадлежат классу, а не экземпляру класса, что означает, что они в некотором смысле являются общими для всего вашего проекта. Но когда вы должны использовать ключевое слово static?


Это основное требование. Если свойство должно иметь независимые значения в нескольких экземплярах, то свойство не может быть статическим.

Однако, если у вас есть, скажем, класс TableCell, который создается один раз для каждой ячейки в макете таблицы, вы можете получить некоторые числовые значения макета, которые одинаковы для каждого TableCell, независимо от содержимого или позиции ячейки. Свойство padding или margin или цвет текста, имя шрифта или цвет фона, скорее всего, не изменятся от экземпляра к экземпляру.

В этом случае вы можете рассмотреть возможность создания статического свойства.


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

Обычно не рекомендуется полагаться на глобальные переменные, так как они могут привести к спагетти-коду, но это не значит, что их нельзя использовать. Иногда самое простое решение — лучшее. Это хорошо работает с константами (см. «Con2-global-access» в исходной загрузке).

Однако для некоторых методов вы можете рассмотреть возможность создания функции пакета, которая в традиционном смысле более глобальна, чем статический метод (см. Пример «con2-package-functions»). Это работает только с функциями, поэтому, если вам нужны глобальные переменные или вам нужно ссылаться на другие члены класса, вам придется использовать статические свойства и методы.


Иногда вам просто нужна функция. Например, рассмотрим следующее:

1
2
3
4
5
6
function removeAllChildren(doc:DisplayObjectContainer):void {
    var num:Number = doc.numChildren;
    for (var i:uint = 0; i < num; i++) {
        doc.removeChildAt(0);
    }
}

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

Flash поставляется с набором классов ослабления в пакете fl.motion.easing . Каждый из этих классов имеет всего три статических метода в соответствии с соглашением об именах easeIn , easeOut и easeInOut . Классы в основном являются контейнерами для хранения функций, используемых в других местах. Нет смысла создавать объект Quadratic , поскольку он существует исключительно для своих статических методов.

См. Пример проекта «con3-utility-functions» для простого, но эффективного класса DisplayObjectUtils в действии.


Иногда необходимо использовать значение, определенное другим объектом в вашем коде. Предположим, у вас есть один объект, который можно настроить одним из двух способов; возможно это кнопка, которая может иметь красный или черный фон. И вы установили этот текст в конструкторе.

Теперь, если бы у вас были свойства, которые действовали как флаги для красного или черного текста, то у вас был бы сценарий «курица и яйцо», когда вы не могли бы получить эти свойства до запуска конструктора, но вы не могли запустить конструктор без этих свойств.

К счастью, статические свойства спасают нас от этой головоломки. Это становится возможным:

1
new StyledButton(StyledButton.RED);

Поскольку в ActionScript отсутствует какой-либо тип перечисления , статические константы обеспечивают следующую лучшую вещь.

Существующим примером этого могут быть имена событий, которые хранятся как статические константы. Например, Event.COMPLETE или MouseEvent.CLICK . Представьте, что вам нужно создавать новое MouseEvent каждый раз, когда вы хотите настроить прослушиватель щелчков. Обратите внимание, что этот пример также попадает под зонтик «только один»; мы, конечно, не хотим, чтобы имя события клика определялось в нескольких местах.

Также см. Проект «con4-enum-values» для пользовательского примера.


Это своего рода комбинация «только один» и «глобальный доступ», так как это своего рода определение Singleton. Тем не менее, я хотел бы отметить, что правильный шаблон проектирования Singleton не является необходимым для достижения подобных эффектов, и что статические методы являются ключом к этому.

Например, класс ExternalInterface состоит из двух статических методов и трех статических свойств ( addCallback() и call() являются методами, а свойства available , marshallExceptions и objectID ). Поскольку для Flash Player существует только один внешний интерфейс, создавать особые экземпляры не нужно. Статические члены здесь имеют большой смысл.

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

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


Теперь, перед тем, как фанаты оптимизации производительности подожгут меня в комментариях, обратите внимание, что существуют некоторые соображения по поводу производительности со статическими членами. В моем тестировании статические члены работают на волосы медленнее, чем члены экземпляра (мы говорим о нескольких миллисекундах за миллион итераций). Тем не менее, другие обнаружили — используя тесты, намного более исчерпывающие мои собственные — что статические члены могут оказать существенное влияние на производительность. Проверьте результаты теста Джексона Данстана или исследование Кристо Дачева по этому вопросу .

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

Другими словами, скажем, Flash Player требуется 10 миллисекунд, чтобы объявить переменную с именем foo как String , а также установить для нее значение String «bar». Это действие займет 10 миллисекунд независимо от того, является ли переменная статической или переменной экземпляра. Итак, в следующем гипотетическом классе QuickTip у нас будет всего 20 миллисекунд, посвященных созданию наших свойств:

1
2
3
4
5
6
7
8
9
package {
    public class QuickTip {
        public static var fooStatic:String = «bar»;
        public var fooInstance:String;
        public function QuickTip() {
            fooInstance = «bar»;
        }
    }
}

Однако эти два свойства занимают свои 10 миллисекунд в разное время. Итак, рассматривая этот другой фрагмент кода (давайте предположим, что это класс документа для нашего SWF):

01
02
03
04
05
06
07
08
09
10
package {
    public class QuickTipTest extends Sprite {
        public function QuickTipTest {
            stage.addEventListener(MouseEvent.CLICK, onClick);
        }
        private function onClick(e:MouseEvent):void {
            var qt:QuickTip = new QuickTip();
        }
    }
}

Поскольку класс QuickTip необходим и включен, fooStatic занимает 10 миллисекунд, пока все остальное инициализируется (объявления классов, объекты, которые создаются сразу же, другие статические члены). Но fooInstance никогда не инициализируется до тех пор, пока не будет нажата стадия, после чего будет QuickTip экземпляр QuickTip .

Это, вероятно, тривиальное различие в большинстве случаев, но я обязан упомянуть об этом. Имейте в виду, что моя точка зрения на этот совет больше касается архитектурных соображений, а не настройки производительности.