Статьи

Мышление в командах: часть 1 из 2

Два раза в месяц мы возвращаемся к любимым постам наших читателей на протяжении всей истории Activetuts +. Это руководство было впервые опубликовано в марте 2010 года и является первой частью серии.

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

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


Инкапсуляция инструкций в «команды» является популярным подходом к программированию для упрощения вещей — шаблон команд на самом деле является одним из наиболее часто используемых шаблонов проектирования в объектно-ориентированном программировании. По сути, концепция команды реализуется путем создания командных классов, каждый класс представляет один тип команды. В остальной части руководства, когда я ссылаюсь на «команду», я имею в виду «объект команды».

Вы можете думать о команде как о кнопке на пульте дистанционного управления. Каждая кнопка делает что-то свое, но все они используются одинаково: вы нажимаете ее, и тогда происходит волшебство. Будь то включение телевизора, переключение каналов или регулировка громкости, все эти функции могут быть выполнены простым нажатием кнопки.

Изображение предоставлено freedigitalphotos.net

Концепция команд такая же. Базовая инструкция команды аналогична функции кнопки пульта дистанционного управления. Вы можете инкапсулировать различные команды в команды, такие как отслеживание простого сообщения, перемещение одного объекта из одного места в другое или переключение видимости экранного объекта. Как только инкапсуляция завершена, это можно выполнить, просто сказав программе «нажать кнопки пульта дистанционного управления» или, другими словами, «выполнить команды».

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


«Большое дело, — скажете вы, — я мог бы сделать это с помощью функций. Зачем использовать команды?» Хорошо, давайте посмотрим на два набора кода, которые создают один и тот же эффект, один с использованием функций, а другой с использованием командной структуры, которую мы создадим в этом руководстве. Преимущество команд станет очевидным.

Допустим, мы хотим создать круг, добавить его на сцену, изменить его от невидимого до видимого в течение полсекунды, подождать две секунды, снова превратить в невидимый в течение еще полсекунды, а затем удалить его со сцены. Чтобы сделать все это, мы будем использовать класс Greensock TweenNano .

Если вы используете только функции, код будет выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
var circle:Circle = new Circle();
addChild(circle);
TweenNano.from(circle, 0.5, {alpha:0, onComplete:func1});
 
function func1():void {
    TweenNano.to(circle, 0.5, {delay:2, alpha:0, onComplete:func2});
}
 
function func2():void {
    removeChild(circle);
}

Видите ли вы, как наш список действий все запутано с нашими инструкциями для выполнения каждого действия? Чтобы понять, что произойдет, вы должны следить за всеми onComplete и посмотреть, куда они ведут.

Вот тот же код с использованием командной структуры:

01
02
03
04
05
06
07
08
09
10
11
var circle:Circle = new Circle();
 
var command:Command =
    new SerialCommand(0,
        new AddChild(this, circle),
        new TweenNanoFrom(circle, 0.5, {alpha:0}),
        new TweenNanoTo(circle, 0.5, {delay:2, alpha:0}),
        new RemoveChild(this, circle)
    );
     
command.start();

Здесь AddChild () , TweenNanoFrom , TweenNanoTo и RemoveChild — это все классы Command, которые мы определяем в другом месте кода, а SerialCommand — еще один класс Command, который мы можем использовать для создания последовательностей команд на лету.

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

Команды также позволяют нам ставить в очередь различные действия, чтобы они выполнялись одновременно — но мы вернемся к этому позже!


Быстрый рабочий пример стоит больше тысячи слов, поэтому давайте посмотрим на основной элемент нашей командной структуры: класс Command.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package commands {
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
     
    public class Command extends EventDispatcher {
         
        private var _timer:Timer;
         
        public function Command(delay:Number = 0) {
            _timer = new Timer(int(1000 * delay), 1);
            _timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);
        }
         
        private function onTimerComplete(e:TimerEvent):void {
            execute();
        }
         
        /**
         * Starts the command.
         * Waits for the timer to complete and calls the execute() method.
         * This method can be used directly as an event listener.
         */
        public final function start(e:Event = null):void {
            _timer.start();
        }
         
        /**
         * The abstract method for you to override to create your own command.
         */
        protected function execute():void {
             
        }
         
        /**
         * Completes the command.
         * Dispatches a complete event.
         * This method can be used directly as an event listener.
         */
        protected final function complete(e:Event = null):void {
            dispatchEvent(new Event(Event.COMPLETE));
        }
    }
}

Метод emptiest — это метод execute (); Однако этот метод является наиболее важной частью команды. Чтобы создавать различные объекты команд, вы должны расширить этот класс Command и переопределить метод execute (), заполнив инструкции, которые должна выполнять ваша программа.

Чтобы заставить объект Command работать, вы вызываете его метод start (); он отсчитывает время задержки с использованием объекта Timer и вызывает метод execute (), когда таймер завершает обратный отсчет. Нулевое время задержки просто означает, что метод execute () вашего объекта Command будет вызываться сразу после вызова его метода start ().

(Обратите внимание, что когда ваша команда завершена, вы должны вызвать метод complete () вручную, чтобы он отправил событие COMPLETE. Назначение этого метода станет понятным позже в этом руководстве.)

Кстати, настройка параметра события для методов start () и complete () с нулевым значением по умолчанию — моя личная привычка. Таким образом, методы могут вызываться так же, как и любые другие методы с нулевым параметром, или могут использоваться непосредственно в качестве прослушивателей событий.


Теперь, когда у нас есть наш класс Command, давайте начнем играть с ним с простой трассировкой.


Прежде всего, мы должны открыть Flash IDE и создать новый документ Flash. Назовите это SimpleTracing.fla.


Затем создайте класс документа для этого документа Flash. Прочтите этот краткий совет для введения в классы документов.

01
02
03
04
05
06
07
08
09
10
package {
    import flash.display.Sprite;
     
    public class SimpleTracing extends Sprite {
         
        public function SimpleTracing() {
             
        }
    }
}

Сохраните его как SimpleTracing.as.


Создайте новый файл AS и скопируйте в него класс Command (сверху).

Создайте новую папку в вашем classpath под названием «команды» и сохраните этот новый файл AS как Command.as внутри этой папки.


Мы хотели бы начать с инкапсуляции функции трассировки в команды, поэтому давайте расширим класс Command, чтобы создать для этой цели класс TraceCommand. Этот класс будет содержать строку сообщения, которая будет отслеживаться при вызове метода execute (), и будет вызывать метод complete () после трассировки.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package commands {
     
    public class TraceCommand extends Command {
         
        private var _message:String;
         
        public function TraceCommand(delay:Number, message:String) {
            super(delay);
            _message = message;
        }
         
        override protected function execute():void {
            trace(_message);
            complete();
        }
    }
}

Сохраните это как TraceCommand.as, также в папке «команды». Посмотрите, как мы переопределили функцию execute (), чтобы эта команда действительно что-то делала?


Завершите класс документа объектами TraceCommand. Добавьте прослушиватели для события COMPLETE этих команд.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package {
    import commands.Command;
    import commands.TraceCommand;
    import flash.display.Sprite;
    import flash.events.Event;
     
    public class SimpleTracing extends Sprite {
         
        public function SimpleTracing() {
             
            var command:Command;
             
            command = new TraceCommand(0, «first command»);
            command.addEventListener(Event.COMPLETE, onCommandComplete);
            command.start();
             
            command = new TraceCommand(1, «second command»);
            command.addEventListener(Event.COMPLETE, onCommandComplete);
            command.start();
             
            command = new TraceCommand(2, «third command»);
            command.addEventListener(Event.COMPLETE, onCommandComplete);
            command.start();
        }
         
        private function onCommandComplete(e:Event):void {
            trace(«a command is complete»);
        }
    }
}

Приказать программе выполнить команды так же просто, как вызвать методы start () объектов Command. Протестируйте фильм, и вы увидите следующий вывод, распечатанный построчно с промежутком времени в одну секунду. Кроме того, вы можете видеть чересстрочные сообщения, распечатанные полным слушателем событий команд. Одна и та же переменная используется для хранения ссылок на разные объекты Command, но программа делает то же самое с переменной: вызывает метод start () и прослушивает событие COMPLETE.


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


Параллельная команда выполняет все свои подкоманды одновременно или, другими словами, параллельно. Команда завершается только тогда, когда все ее подкоманды завершены. На следующем рисунке представлена ​​визуальная концепция параллельной команды. Черные стрелки обозначают «поток» выполнения команды


Теперь пришло время создать наш класс для параллельных команд.

Ниже приведен полный код класса ParallelCommand. Сохраните его как ParallelCommand.as в папке «команды».

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package commands {
    import flash.events.Event;
     
    public class ParallelCommand extends Command {
         
        private var _commands:Array;
         
        public function ParallelCommand(delay:Number, …commands) { //…commands is the «…(rest)» parameter
            super(delay);
            _commands = commands;
        }
         
        private var _completeCommandCount:int;
         
        override final protected function execute():void {
             
            //set the complete command count to zero
            _completeCommandCount = 0;
             
            for each (var command:Command in _commands) {
                 
                //listen for the complete event of a subcommand…
                command.addEventListener(Event.COMPLETE, onSubcommandComplete);
                 
                //…and start the subcommand
                command.start();
            }
        }
         
        private function onSubcommandComplete(e:Event):void {
             
            //stop listening for the complete event
            Command(e.target).removeEventListener(Event.COMPLETE, onSubcommandComplete);
             
            //increment the complete command count
            _completeCommandCount++;
             
            //if all the commands are complete…
            if (_completeCommandCount == _commands.length) {
                 
                //…then this parallel command is complete
                complete();
            }
        }
    }
}

Этот класс переопределяет метод execute (); новый метод execute () теперь вызывает метод start () всех подкоманд и прослушивает их события COMPLETE. Слушатель события COMPLETE для подкоманд подсчитывает, сколько подкоманд выполнено; когда все подкоманды выполнены, вызывается метод complete () ParallelCommand, который отправляет собственное событие COMPLETE.


Давайте попробуем класс ParallelCommand. Создайте новый документ Flash, скопируйте папку «commands» в ее путь к классу и напишите новый класс документа, как показано ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package {
    import commands.Command;
    import commands.ParallelCommand;
    import commands.TraceCommand;
    import flash.display.Sprite;
    import flash.events.Event;
     
    public class ParallelTracing extends Sprite {
         
        public function ParallelTracing() {
             
            var parallelCommand:Command =
                new ParallelCommand(0,
                    new TraceCommand(0, «1st of 3»),
                    new TraceCommand(0, «2nd of 3»),
                    new TraceCommand(0, «3rd of 3»),
                );
                 
            parallelCommand.addEventListener(Event.COMPLETE, onCommandComplete);
             
            parallelCommand.start();
        }
         
        private function onCommandComplete(e:Event):void {
            trace(«all commands are complete»);
        }
    }
}

Преимущество использования параметра «… (rest)» для параметра конструктора теперь становится очевидным. Вы можете отформатировать подкоманды с соответствующим отступом кода, чтобы писать визуально понятные коды.

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

  • 1 из 3
  • 2 из 3
  • 3 из 3
  • все команды выполнены

Как насчет настройки задержек в параллельной команде? Просто. Измените функцию конструктора вашего класса документа следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public function ParallelTracing() {
     
    var parallelCommand:Command =
        new ParallelCommand(0,
            new TraceCommand(0, «first wave, 1st of 2»),
            new TraceCommand(0, «first wave, 2nd of 2»),
            new TraceCommand(1, «second wave, 1st of 3»),
            new TraceCommand(1, «second wave, 2nd of 3»),
            new TraceCommand(1, «second wave, 3rd of 3»),
            new TraceCommand(2, «last wave, 1st of 2»),
            new TraceCommand(2, «last wave, 2nd of 2»)
        );
         
    parallelCommand.addEventListener(Event.COMPLETE, onCommandComplete);
     
    parallelCommand.start();
}

Протестируйте фильм, и вы увидите следующие три волны сообщений с интервалом в одну секунду между каждой волной:

  • первая волна, 1 из 2
  • первая волна, 2 из 2

  • вторая волна, 1 из 3
  • вторая волна, 2 из 3
  • вторая волна, 3 из 3

  • последняя волна, 1 из 2
  • последняя волна, 2 из 2

Чтобы лучше понять, что происходит, посмотрите на эту иллюстрацию:


Второй тип составной команды — это последовательная команда. Последовательная команда выполняет свои подкоманды одну за другой — или, другими словами, последовательно. Например, вторая команда выполняется после завершения первой, а третья — после завершения второй. На следующем рисунке представлена ​​визуальная концепция последовательной команды:


Вот исходный код для класса SerialCommand. Переопределенный метод execute () вызывает метод start () первой подкоманды и прослушивает событие COMPLETE. Затем прослушиватель событий запускает следующую подкоманду и прослушивает событие COMPLETE и т. Д., Пока все подкоманды не будут выполнены. В этот момент отправляется событие COMPLETE для всей SerialCommand.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package commands {
    import flash.events.Event;
     
    public class SerialCommand extends Command {
         
        private var _commands:Array;
         
        public function SerialCommand(delay:Number, …commands) {
            super(delay);
            _commands = commands;
        }
         
        private var _completeCommandCount:int;
         
        override final protected function execute():void {
             
            //set the complete command count to zero
            _completeCommandCount = 0;
             
            //listen for the complete event of the first subcommand…
            _commands[0].addEventListener(Event.COMPLETE, onSubcommandComplete);
             
            //…and start the subcommand
            _commands[0].start();
        }
         
        private function onSubcommandComplete(e:Event):void {
             
            //stop listening for the complete event
            Command(e.target).removeEventListener(Event.COMPLETE, onSubcommandComplete);
             
            //increment the complete command count
            _completeCommandCount++;
             
            //if all the commands are complete…
            if (_completeCommandCount == _commands.length) {
                 
                //…then this serial command is complete
                complete();
            } else {
                 
                //…otherwise listen for the complete event of the next subcommand…
                _commands[_completeCommandCount].addEventListener(Event.COMPLETE, onSubcommandComplete);
                 
                //…and start the subcommand
                _commands[_completeCommandCount].start();
            }
        }
    }
}

Давайте использовать класс SerialCommand для выполнения последовательной трассировки. Как и прежде, создайте новый документ Flash, скопируйте папку «команды» и напишите новый класс документа:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package {
    import commands.Command;
    import commands.SerialCommand;
    import commands.TraceCommand;
    import flash.display.Sprite;
    import flash.events.Event;
     
    public class SerialTracing extends Sprite {
         
        public function SerialTracing() {
             
            var serialCommand:Command =
                new SerialCommand(0,
                    new TraceCommand(0, «first command»),
                    new TraceCommand(1, «second command»),
                    new TraceCommand(1, «third command»)
                );
                 
            serialCommand.addEventListener(Event.COMPLETE, onCommandComplete);
             
            serialCommand.start();
        }
         
        private function onCommandComplete(e:Event):void {
            trace(«all commands are complete»);
        }
    }
}

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

  • первая команда

  • вторая команда

  • третья команда

Вот концептуальная фигура этого примера, которая поможет вам лучше понять, что происходит.


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


Как и прежде, создайте новый документ Flash, скопируйте папку «команды» и напишите новый класс документа:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package {
    import commands.Command;
    import commands.ParallelCommand;
    import commands.SerialCommand;
    import commands.TraceCommand;
    import flash.display.Sprite;
    import flash.events.Event;
     
    public class NestedCommands extends Sprite {
         
        public function NestedCommands() {
             
            var nestedCommands:Command =
                new SerialCommand(0,
                    new ParallelCommand(0,
                        new TraceCommand(0, «parallel command #1, part 1 of 2»),
                        new TraceCommand(0, «parallel command #1, part 2 of 2»),
                        new TraceCommand(0, «———————————«)
                    ),
                    new ParallelCommand(1,
                        new TraceCommand(0, «parallel command #2, part 1 of 3»),
                        new TraceCommand(0, «parallel command #2, part 2 of 3»),
                        new TraceCommand(0, «parallel command #2, part 3 of 3»),
                        new TraceCommand(0, «———————————«)
                    ),
                    new ParallelCommand(1,
                        new TraceCommand(0, «last command»),
                        new TraceCommand(0, «———————————«)
                    )
                );
                 
            nestedCommands.addEventListener(Event.COMPLETE, onCommandComplete);
             
            nestedCommands.start();
        }
         
        private function onCommandComplete(e:Event):void {
            trace(«all commands are complete»);
        }
    }
}

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

  • параллельная команда № 1, часть 1 из 2
  • параллельная команда № 1, часть 2 из 2
  • ———————————

  • параллельная команда № 2, часть 1 из 3
  • параллельная команда № 2, часть 2 из 3
  • параллельная команда № 2, часть 3 из 3
  • ———————————

  • последняя команда
  • ———————————

Вот концептуальная фигура этого примера.


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


Создайте символ фрагмента ролика с анимацией временной шкалы, где цвет круга меняется с серого на желтый.

На временной шкале на последнем ключевом кадре добавьте следующий код. Это приводит к прекращению анимации фрагмента ролика и отправке события ЗАВЕРШЕНО:

1
2
stop();
dispatchEvent(new Event(Event.COMPLETE));

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

1
2
3
4
5
public function reachedEndOfAnimation():void
{
    stop();
    dispatchEvent(new Event(Event.COMPLETE));
}

… а затем в конструкторе этого класса напишите следующее:

1
addFrameScript(4, reachedEndOfAnimation) //where 4 is one less than the number of frames

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


Перетащите компонент Button с панели компонентов на сцену и назовите его «start_btn». Мы хотим выполнить наши команды, когда эта кнопка нажата.


Создайте текстовое поле на сцене и введите сообщение о завершении. Затем преобразуйте его в символ фрагмента ролика и назовите экземпляр «completeMessage_mc».


Теперь пришло время редактировать класс документа. Объявите частную переменную «circuitCommand», которая будет использоваться для хранения ссылки на объект Command:

1
private var circuitCommand:Command;

В начале программы все источники света должны быть выключены, т.е. остановлены в первом кадре, а сообщение о завершении должно быть скрыто. Поэтому мы вызываем метод reset () в конструкторе.

1
reset();

Затем создайте наши вложенные команды, которые воспроизводят анимацию легких фрагментов ролика, освещая их с надлежащей синхронизацией. Здесь мы используем класс PlayCommand, который просто вызывает метод play () фрагмента ролика. Мы напишем класс позже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
circuitCommand =
    new SerialCommand(0.5,
        new PlayCommand(0, light_1),
        new ParallelCommand(0.5,
            new PlayCommand(0, light_2_1),
            new PlayCommand(0, light_2_2)
        ),
        new PlayCommand(0.5, light_3),
        new ParallelCommand(0.5,
            new PlayCommand(0, light_4_1),
            new PlayCommand(0, light_4_2)
        ),
        new PlayCommand(0.5, light_5)
    );

Затем прослушайте событие COMPLETE команды и событие CLICK кнопки запуска:

1
2
circuitCommand.addEventListener(Event.COMPLETE, onCommandComplete);
start_btn.addEventListener(MouseEvent.CLICK, startCircuit);

Показать сообщение о завершении, когда команда завершена:

1
2
3
private function onCommandComplete(e:Event):void {
    completeMessage_mc.visible = true;
}

Перезагрузите цепь и начните команду, когда нажата кнопка запуска.

1
2
3
4
private function startCircuit(e:MouseEvent):void {
    reset();
    circuitCommand.start();
}

Последняя часть класса документа — метод reset (). Ничего общего с командами здесь.

01
02
03
04
05
06
07
08
09
10
11
private function reset():void {
    completeMessage_mc.visible = false;
     
    light_1.gotoAndStop(1);
    light_2_1.gotoAndStop(1);
    light_2_2.gotoAndStop(1);
    light_3.gotoAndStop(1);
    light_4_1.gotoAndStop(1);
    light_4_2.gotoAndStop(1);
    light_5.gotoAndStop(1);
}

Последняя часть этого примера — класс PlayCommand. Как упоминалось ранее, он просто вызывает метод play () фрагмента ролика. Как только метод play () вызывается в переопределенном методе execute () команды, также вызывается метод complete ().

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package commands {
    import flash.display.MovieClip;
    import flash.events.Event;
     
    public class PlayCommand extends Command {
         
        private var _movieClip:MovieClip;
         
        public function PlayCommand(delay:Number, movieClip:MovieClip) {
            super(delay);
            _movieClip = movieClip;
        }
         
        override protected function execute():void {
            _movieClip.addEventListener(Event.COMPLETE, complete);
            _movieClip.play();
        }
    }
}

Сохраните это как PlayCommand.as в вашей папке «команд».


Хорошо, мы сделали! Теперь протестируйте фильм, и вы увидите, как загораются огни слева направо после нажатия кнопки запуска. Сообщение о завершении отображается, когда все огни загорелись.

Вот визуальное представление того, что происходит в этом примере:

Сравните его с реальным кодом и посмотрите, как легко это понять:

01
02
03
04
05
06
07
08
09
10
11
12
13
new SerialCommand(0.5,
    new PlayCommand(0, light_1),
    new ParallelCommand(0.5,
        new PlayCommand(0, light_2_1),
        new PlayCommand(0, light_2_2)
    ),
    new PlayCommand(0.5, light_3),
    new ParallelCommand(0.5,
        new PlayCommand(0, light_4_1),
        new PlayCommand(0, light_4_2)
    ),
    new PlayCommand(0.5, light_5)
);

Опять же, при правильном отступе кода сложная вложенная команда может быть выражена как простой и чистый код.


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

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


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

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