Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Вопрос об архитектуре приложения (http://www.flasher.ru/forum/showthread.php?t=210113)

djken 29.01.2015 01:10

Вопрос об архитектуре приложения
 
Всем привет.

Например, у меня есть основной класс документа Main, где пишу весь основной скрипт.
В него вложена некая панель BlackList.
В панель вложено множество кнопок ItemBlackList.

Вопросы такие:
1. Правильно ли, что я в классе ItemBlackList подписываюсь на события MOUSE_OVER и MOUSE_OUT, а CLICK слушаю в его родительском классе BlackList ? Как я понимаю - дочерний объект не должен влиять на родителя. Как правильно разграничить действия между родителем и дочерними объектами - что должен знать родитель, а что его ребенок?

2. По нажатию на любой из ItemBlackList, в файл blacklist.xml должны записываться некие данные. Но этот XML файл подгружен в классе Main. Как правильнее делать - передавать данные через всю цепочку ItemBlackList -> BlackList -> Main ?? Или же Main не обязан знать что нужно делать с файлом, а всю работу с файлом должен брать на себя класс BlackList ??

Не знаю - правильно ли делать так?
И как в данном случае, например, узнать, какая из множества кнопок была нажата?

Класс Main:
Код AS3:

blackList = new BlackList();
addChild(blackList);
blackList.addEventListener("ITEM_BLACKLIST_CLICK", itemBlackListClick);
 
private function itemBlackListClick(e:Event):void {
        trace("ITEM CLICK");
}

Класс BlackList:
Код AS3:

itemBlackList = new ItemBlackList();
itemBlackList.addEventListener(MouseEvent.CLICK, itemClick);
 
private function itemClick(e:MouseEvent):void {
        dispatchEvent(new Event("ITEM_BLACKLIST_CLICK"));
}


ZackMercury 29.01.2015 03:22

Вам не обязательно думать, что должен знать родитель, а что ребёнок.
Достаточно просто представить проект как список объектов/компонентов. Вы пользуетесь ихними методами и свойствами и вас абсолютно не интересует, как они устроены внутри.

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

Код AS3:

var checkBox:CheckBox = new CheckBox(true, true); //(активен, значение флажка)
checkBox.state = false; //снимаем галочку
checkBox.enabled = false; //делаем чекбокс неактивным
addChild(checkBox); //добавляем его в дисплейлист
 
trace(checkBox.state);

То же со скроллбаром, или к примеру кнопкой, слайдером, хп-мана-exp-барами,
Да, вполне логично, что
Цитата:

1. Правильно ли, что я в классе ItemBlackList подписываюсь на события MOUSE_OVER и MOUSE_OUT, а CLICK слушаю в его родительском классе BlackList ?
Но при этом приведённый выше чекбокс должен сам знать, что при клике по нему он должен менять свой state и визуальное отображение. При этом родитель может выполнять свои действия при клике на него, или наведении, подписываясь на клик снаружи.

PHP код:

2. По нажатию на любой из ItemBlackListв файл blacklist.xml должны записываться некие данныеНо этот XML файл подгружен в классе MainКак правильнее делать передавать данные через всю цепочку ItemBlackList -> BlackList -> Main ?? Или же Main не обязан знать что нужно делать с файлома всю работу с файлом должен брать на себя класс BlackList ?? 

В таком случае, слушать нажатие должен только класс, в котором хранятся ссылки на ItemBlackList.
Можно в BlackList отправлять событие, что была нажата кнопка и сохранять какая именно кнопка в публичную переменную.
Main пусть слушает BlackList и изменяет xml.

callme 29.01.2015 10:50

Допустим есть три кнопки. По нажатию на первую рисуем квадрат, на вторую - треугольник, на третью - круг.

На Main addChild спрайт. А уже на этот спрайт addChild панель.

Спрайт подписывается на события панели и рисует фигуры.
PanelEvents.DRAW_SQUARE
PanelEvents.DRAW_TRIANGLE
PanelEvents.DRAW_CIRCLE

Кнопка сама себя подписывает на CLICK. При клике диспатчит одно из событий панели.

Либо панель подписывает конкретную кнопку на CLICK (но не себя). При клике диспатчит одно из событий панели.

P.S.
Но если вам нужно в xml гнать просто текст на кнопке. То можно и саму панель подписать на клик.
Код AS3:

function onClick(e:MouseEvent):void
{
    dispatchEvent( new Event( MyButton(e.target).text ) );
}


djken 29.01.2015 14:59

Как быть, если, например, вложенность намного больше и на самом главном уровне нужно ловить событие самого последнего вложенного объекта? На каждом уровне подписываться на событие ребенка и диспатчить его для родителя?

callme 29.01.2015 15:28

Можно ловить событие, когда оно в фазе захвата.
Третий параметр в addEventListener().

Код AS3:

sprite1.addEventListener('someEvent', sprite1_someevent, true);

Код AS3:

package
{
    import flash.display.Sprite;
    import flash.events.Event;
 
    public class Main extends Sprite
    {
        public function Main()
        {
            var sprite1:Sprite = new Sprite();
            var sprite2:Sprite = new Sprite();
            var sprite3:Sprite = new Sprite();
            var sprite4:Sprite = new Sprite();
 
            addChild(sprite1);
            sprite1.addChild(sprite2);
            sprite2.addChild(sprite3);
            sprite3.addChild(sprite4);
 
            sprite1.addEventListener('someEvent', sprite1_someevent, true);
 
            sprite4.dispatchEvent( new Event('someEvent') );
        }
 
        private function sprite1_someevent(e:Event):void
        {
            trace("function sprite1_someevent()");
        }
    }
}


Wolsh 29.01.2015 15:52

Лучше, конечно же, продумывать приложение иерархически, чтобы Императору не приходилось звонить каждому солдату в окоп и уж тем более наоборот. Разделяйте ответственность, назначайте командиров, устанавливайте порядок и направление отчетности. У каждого должна быть своя зона ответственности, и она определяется еще на уровне выделения Класса как сущности. В мире флэш это конечно немного не так абстрактно, из-за обилия визуальных объектов возникает некая растерянность, к кому/к чему "привязывать" логику. Надо всё же как-то разделить действия, ответственность, чтобы кнопка "только нажималась", панель кнопок "только сообщала о выборе", а решения принимал тот, кто эту панель кнопок и создал для интерфейса с пользователем. Если у Вас Мейн должен знать все о какой-то тридевятой кнопке в тридесятом контейнере, значит Вы не разделили ответственность по объектам и Мейн перегружен. Ему нужны министры, а министрам — менеджеры, организовывающие персонал. Создавайте цепочки иерархии, компануйте однотипные задачи, не валите все в одну кучу Мейн.

callme 29.01.2015 16:30

Цитата:

Сообщение от Wolsh (Сообщение 1178140)
Лучше, конечно же, продумывать приложение иерархически, чтобы Императору не приходилось звонить каждому солдату в окоп и уж тем более наоборот.

Как избавиться от глобальных переменных?

Пример:

В библиотеке Starling есть хранилище ассетов. Я кладу этот объект в глобальную переменную потому что мне придется обращаться к этому хранилищу много где.

new MovieClip(globalAssetStore);

Можно передавать этот assetStore в конструкторы, которые передадут этот объект во вложенные конструкторы. Но код становится нечитабельным.

ZackMercury 29.01.2015 18:13

Цитата:

Кнопка сама себя подписывает на CLICK. При клике диспатчит одно из событий панели.
Что за ерунда? Где логика?
Кнопка не знает ничего о панели, она лишь знает свою функцию.
Можно вызывать callBack() внутри кнопки, на который сделать сеттер onClick = someFunc;
Но колбеки делают код неоднородным, а поэтому лучше подписываться на клик в двух местах - снаружи кнопки для того, чтобы знать, когда менять xml и внутри кнопки, чтобы к примеру менять визуальное отображение и состояние.

Предлагаю сделать ещё интересней,
Код AS3:

package 
{
        import flash.display.Sprite;
 
        /**
        * ...
        * @author ZackMercury
        */

        public class Panel extends Sprite
        {
                private static const OFFSET_BETWEEN_BUTTONS:int = 5;
 
                private var _buttons:Vector.<Button>;
 
                public function Panel()
                {
                        _buttons = new Vector.<Button>();
                }
 
                public function addButton(caption:String, onClick:Function):void
                {
                        var btn:Button = new Button(caption);
                        btn.onClick = onClick;
                        addChild(btn);
                        _buttons.push(btn);
 
                        update();
                }
 
                public function removeButton(caption:String):void
                {
                        for (var i:int = 0; i < _buttons.length; i ++)
                        {
                                if (_buttons[i].caption == caption)
                                {
                                        removeChild(_buttons[i]);
                                        _buttons.splice(i, 1);
                                }
                        }
 
                        update();
                }
 
                private function update():void
                {
                        for (var i:int = 0; i < _buttons.length; i ++)
                        {
                                _buttons[i].y = (_buttons[i].height + OFFSET_BETWEEN_BUTTONS) * i;
                        }
                }
        }
 
}

Код AS3:

package 
{
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
 
        /**
        * ...
        * @author ZackMercury
        */

        public class Main extends Sprite
        {
                public function Main()
                {
                        if (stage) init();
                        else addEventListener(Event.ADDED_TO_STAGE, init);
                }
 
                public function init(e:Event = null):void
                {
                        if (hasEventListener(Event.ADDED_TO_STAGE)) removeEventListener(Event.ADDED_TO_STAGE, init);
                        //entry
                        var panel:Panel = new Panel();
                        panel.addButton("Start game", buttonClicked);
                        panel.addButton("Exit", buttonClicked);
                        panel.addButton("Options", buttonClicked);
                        panel.removeButton("Options");
                        addChild(panel);
                }
 
                private function buttonClicked(e:MouseEvent):void
                {
                        switch((e.target as Button).caption)
                        {
                                case "Start game":
                                        //начинаем игру
                                        break;
                                case "Exit":
                                        //выходим из игры
                                        break;
                                default:
                                        throw new Error("No action for this button");
                        }
                }
        }
}


callme 29.01.2015 18:32

to djken, я ошибся, надо делать как SuriTheAngel говорит.

Добавлено через 1 час 30 минут
SuriTheAngel
Мне кажется пусть лучше панель свои кнопки создает. Какие преимущества есть у твоего подхода?

ZackMercury 29.01.2015 21:17

PHP код:

Какие преимущества есть у твоего подхода

Это не мой подход, а подход с точки зрения Объектно-Ориентированного Программирования. (ООП)
Преимущества. Даже лень перечислять...

1) Можно эту же панель не переписывая использовать в любых других проектах, ведь кнопки создаются через методы addButton() и удаляются через removeButton() снаружи панели.
2) Логично, что панель выполняет лишь свои функции - является панелью, в которую можно добавить кнопки или удалить из неё кнопки.
3) Логично, что кнопки являются кнопками и выполняют лишь свою функцию, не меняют никаких xml.
4) Конечно, В КРАЙНЕМ СЛУЧАЕ, НУ ВДРУГ НУ ВООБЩЕ ППЦ КАК НАДА БУДИТ, можно создавать кнопки в панели, используя её же методы из конструктора =) Для справки)
5) Скачав классы Panel, Button не нужно лезть внутрь этих классов, чтобы знать как ими пользоваться. Достаточно написать var panel:Panel = new Panel();
напишите
panel.
И среда(FlashDevelop) сама подсказывает, какие есть методы у этого класса. И из их названий точно и ясно, что они делают.
addButton() в переводе значит "добавить кнопку", для справки.
removeButton() в переводе "убрать кнопку".
набор передаваемых аргументов тоже достаточно ясно описан и подсказывается средой=)

взгляните на код
Код AS3:

public function init(e:Event = null):void
                {
                        if (hasEventListener(Event.ADDED_TO_STAGE)) removeEventListener(Event.ADDED_TO_STAGE, init);
                        //entry
                        var panel:Panel = new Panel();
                        panel.addButton("Start game", buttonClicked);
                        panel.addButton("Exit", buttonClicked);
                        panel.addButton("Options", buttonClicked);
                        panel.removeButton("Options");
                        addChild(panel);
                }
 
                private function buttonClicked(e:MouseEvent):void
                {
                        switch((e.target as Button).caption)
                        {
                                case "Start game":
                                        //начинаем игру
                                        break;
                                case "Exit":
                                        //выходим из игры
                                        break;
                                default:
                                        throw new Error("No action for this button");
                        }
                }

Разве из него не сразу ясно, что он делает? Задача программиста - упрощать себе работу, а не усложнять.
Поэтому мы пишем набор инструментов, подобно классу Button(кнопка) или Panel(панель).
При желании можно добавить классу Panel свойство orientation
и 2 константы - Panel.HORIZONTAL, Panel.VERTICAL.
Они будут определять, как будут располагаться кнопки - горизонтально или вертикально.
Вот так вот мы и работаем)
Улучшаем наши инструменты потихоньку.
Потом мы можем в любой проект сунуть эти классы и они будут работать.
Чтобы не копаться в их коде, мы пишем снаружи все обработчики кликов и пользуемся их свойствами и методами.

P.S. Если хотите проверить, как будет работать код - могу ещё дописать класс Button :)


Часовой пояс GMT +4, время: 20:42.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.