AS3 / Flash: не плохо ли дочерним компонентам вызывать методы своих родителей? - PullRequest
0 голосов
/ 04 февраля 2010

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

Здесь у меня есть родительский класс, который создает экземпляр класса MenuClass и обрабатывает переходы между страницами.

public class ParentClass extends Sprite
{
    public function ParentClass()
    {
        setupOptionMenu();
    }

    private function setupOptionMenu() : void
    {
        var myMenu:MenuClass = new MenuClass;
        myMenu.setUpButtons();
        this.addChild( myMenu );
    }

    + public function transitionForward() : void

    + public function transitionBackward() : void
}

А вот MenuClass, который создает кнопки вперед и назад. Нажатие каждого скажет вышеупомянутому ParentClass переходу () или переходу () соответственно.

public class MenuClass extends Sprite
{
    public function MenuClass()
    {
        setupButtons();
    }

    public function setUpButtons() : void
    {
        var backButton:Button = new Button();
        backButton.addEventListener( MouseEvent.CLICK, backClick );
        addChild( backButton );

        var forwardButton:Button = new Button();
        forwardButton.addEventListener( MouseEvent.CLICK, forwardClick );
        addChild( forwardButton );
    }

    private function backClick( e:Event ) : void
    {
        ParentClass( this.parent ).transitionForward();
    }

    private function forwardClick( e:Event ) : void
    {
        ParentClass( this.parent ).transitionBackward();
    }
}

С одной стороны, я чувствую, что MenuClass слишком тесно связан со своим родителем и, следовательно, менее пригоден для повторного использования. С другой стороны, я чувствую, что в интересах сохранения всего самодостаточного, ParentClass не несет ответственности за доступ к экземпляру MenuClass и добавление туда прослушивателей событий. Похоже, должно быть какое-то эмпирическое правило ООП, чтобы управлять такими отношениями.

Итак, мой вопрос: слишком ли тесно связан мой MenuClass с его родителем? И если да, есть ли у вас какие-либо предложения, которые ослабили бы эту связь?

Спасибо.

Ответы [ 4 ]

5 голосов
/ 05 февраля 2010

Если есть шанс, что вы захотите предложить несколько способов навигации (помимо только меню), тогда имеет смысл использовать подход, основанный на событиях. Это позволяет вам практически полностью отделить Родителя от Меню.

Вот код, который я на самом деле тестировал во Flash. ;)

Родитель создает объект меню и прослушивает события FORWARD и BACKWARD из него:

package  
{
        import flash.display.Sprite;
        import flash.events.Event;

        public class ParentClass extends Sprite
        {
            public function ParentClass() 
            {
                setupOptionMenu();
            }

            private function setupOptionMenu() : void
            {
                var myMenu:MenuClass = new MenuClass;
                myMenu.setUpButtons();
                this.addChild( myMenu );

                myMenu.addEventListener(MenuClass.FORWARD, transitionForward);
                myMenu.addEventListener(MenuClass.BACKWARD, transitionBackward);
            }

            public function transitionForward(e:Event) : void
            { 
                trace("forward");
            }

            public function transitionBackward(e:Event) : void
            {
                trace("backward");
            }
        }
}

Затем MenuClass отправляет эти события, когда что-то нажимается:

package  
{
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.display.SimpleButton;

        public class MenuClass extends Sprite
        {
            public static const FORWARD:String = "forward";
            public static const BACKWARD:String = "backward";

            public function MenuClass() 
            {
                setUpButtons();
            }

            public function setUpButtons() : void
            {
                var rect:Sprite = new Sprite();
                rect.graphics.beginFill(0x666666);
                rect.graphics.drawRect(0,0,50,20);

                var backButton:SimpleButton = new SimpleButton(rect, rect, rect, rect);
                backButton.x = 10;
                backButton.y = 10;
                backButton.addEventListener( MouseEvent.CLICK, backClick );
                addChild( backButton );

                var forwardButton:SimpleButton = new SimpleButton(rect, rect, rect, rect);
                forwardButton.x = 70;
                forwardButton.y = 10;
                forwardButton.addEventListener( MouseEvent.CLICK, forwardClick );
                addChild( forwardButton );
            }

            private function backClick( e:MouseEvent ) : void
            {
                dispatchEvent(new Event(BACKWARD));
            }

            private function forwardClick( e:MouseEvent ) : void
            {
                dispatchEvent(new Event(FORWARD));
            }
        }
}

Чтобы предоставить альтернативные методы пользовательского интерфейса, такие как сочетания клавиш или контекстные меню и т. Д., Просто отправьте одни и те же события FORWARD и BACKWARD и попросите их прослушать также Parent. Вы также можете создать новый подкласс Event и поместить туда константы FORWARD и BACKWARD, если хотите.

1 голос
/ 04 февраля 2010

С другой стороны, мне кажется, что в интересах сохранения всего самодостаточного, ParentClass не несет ответственности за доступ к экземпляру MenuClass и добавление туда прослушивателей событий.

Почему бы и нет? Если ParentClass должен прослушивать события в MenuClass, он должен сам добавлять тех, кто прослушивает события. Либо путем непосредственного вызова addEventListener, либо вызова другого метода в MenuClass, который устанавливает обработчики событий с нужной функцией для вызова.

0 голосов
/ 05 февраля 2010

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

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

Я большой поклонник статических методов и классов Manager, но есть целая группа людей, которые в равной степени против этого или хуже, чем вызовы метода child-> parent.

Важно отметить, что "parent" - это свойство, которое зависит от addChild () и списка отображения.

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

Еще одна странность заключается в том, что если вы добавляете дочерний элемент в список отображения, а затем УДАЛЯЕТЕ его, родительский элемент все равно устанавливается на последний объект, к которому он был добавлен, поэтому он может быть в состоянии предпринять действия против объекта, который технически больше не ребенок.

Вот почему я обычно формулирую эту логику следующим образом

if(Type(this.parent).contains(this))
{
//do stuff
}

Contains будет возвращать только значение true, если объект находится в списке отображения.

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

0 голосов
/ 04 февраля 2010

ИМХО, вы можете сделать это, если ваше приложение является маленьким / средним, для больших проектов вы правы в разделении родительского класса и дочернего класса. Существует несколько подходов, основанных на вкусе, один из которых заключается в создании класса FlowControl.

public class FlowControl
{
   private var _parentSprite : ParentClass;
   private var _instance : FlowControl;

   public static FlowControl GetInstance(ParentSprite : ParentClass)
   {

        if (_instance == null)
            _instance = new FlowControl(ParentSprite);
        return _instance;

   }

   private FlowControl(ParentSprite : ParentClass)
   {
       _parentSprite = ParentSprite;
   }

   public static void NextPage()
   {
       ParentSprite.transitionForward();
   }
}

У меня нет вспышки, чтобы проверить это, но вы поняли.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...