松散耦合的Flex 3兄弟组件

时间:2009-02-02 15:36:27

标签: flex actionscript-3

我正在创建一个应用程序,其中有两个mxml组件MainPanel.mxml和TextPanel.mxml,它们包含在名为index.mxml的父应用程序中。当我输入TextPanel.mxml中存在的文本框时,我希望能够将此数据绑定到TextPanel.mxml中存在的标签。我知道这可以通过以下方式完成:

<mx:Label text="{Application.application.textArea.text1.text}" />

但是,我想让我的组件更容易与系统交换,这会创建我不想要的依赖项。

以下是我提出的解决方案,虽然我觉得有更好的方法(为简洁起见省略了一些代码)。

index.mxml(父应用程序):

<mx:Script>
    <![CDATA[

        [Bindable]
        private var _text:String;

        private function handleTextChange(input:String):void {
            _text = input;
        }

    ]]>
</mx:Script>

<tp:TextPanel id="textArea" 
    textChange="handleTextChange(event.stringData)"/>

<cp:MainPanel id="mainArea" text = "{_text}" />

TextPanel.mxml:

<mx:Metadata>
    [Event(name="textChange", type="events.CustomStringDataEvent")]
</mx:Metadata>

<mx:Script>
    <![CDATA[
        import events.CustomStringDataEvent;
        private function textChangeHandler(event:Event):void {
            var input:String = event.target.text;
            dispatchEvent(new CustomStringDataEvent(input, 'textChange'));
        }
    ]]>
</mx:Script>
<mx:TextInput id="text1" change="textChangeHandler(event)"/>

MainPanel.mxml

<mx:Script>
    <![CDATA[

        [Bindable]
        public var text:String;

    ]]>
</mx:Script> 
<mx:Label text="{text}" />

最后我的问题是,在两个兄弟组件之间创建松散耦合的最佳做法是什么?

2 个答案:

答案 0 :(得分:2)

这是一种做法,当然。但是你也可以创建另一个类来保存由一个(或任何)组件写入的数据,然后为每个组件提供对该对象的引用;这可以通过少量代码和手动事件处理获得相同的效果。

例如,保存数据的类对象可能如下所示(请注意公共成员上的Bindable属性:

package
{
    public class MyBindableObject
    {
        [Bindable]
        public var myStringProperty:String = "";        

        public function MyBindableObject()
        {
            //
        }   
    }
}

...和你的主应用程序容器,它最初将实例化对象(并分发对其子组件的引用),如下所示:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:local="*" initialize="this_initialize(event)">

    <mx:Script>
        <![CDATA[

            [Bindable]
            private var myObject:MyBindableObject;

            private function this_initialize(event:Event):void
            {
                myObject = new MyBindableObject();
            }

        ]]>
    </mx:Script>

    <mx:TextInput text="{myObject.myStringProperty}" />
    <local:MyCustomComponent myObject="{myObject}" />
    <local:MyOtherCustomComponent myObject="{myObject}" />

</mx:WindowedApplication>

...和MyCustomComponent(请注意Bindable&amp; Inspectable属性),在这种情况下恰好直接写入myObject.myStringProperty

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Script>
        <![CDATA[

            [Bindable]
            [Inspectable]
            public var myObject:MyBindableObject;

            private function myEventHandler(event:Event):void
            {
                myObject.myStringProperty = txt.text;
            }

        ]]>
    </mx:Script>

    <mx:TextInput id="txt" text="{myObject.myStringProperty}" keyUp="myEventHandler(event)" />

...和MyOtherCustomComponent,它接收前一个组件中所做的更改(并且偶然传播到容器应用程序):

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Script>
        <![CDATA[

            [Bindable]
            [Inspectable]
            public var myObject:MyBindableObject;

        ]]>
    </mx:Script>

    <mx:TextInput text="{myObject.myStringProperty}" />

</mx:Canvas>

同样,容器应用程序初始化对象实例,将其自己的子组件属性之一绑定到该对象的属性值(可选),并将对该对象的引用交给其子组件可能想要使用它的任何子组件。在这种情况下,第二个组件写入值,另外两个组件立即获得更改,因为MyBindableObject类上的myStringProperty标记为Bindable,并且每个组件都包含一个用于更改该属性的侦听器。

这个例子有点简单,因为它只是在某个对象上设置一个字符串值,从而将事件派发工作卸载到Flex框架,这只消除了几行代码 - 但这可能是一件好事因为实际上没有必要为简单的文本更改/属性更改事件设计自定义事件,因为Flex会为您处理大部分甚至全部工作。

然而,它仍取决于您希望自定义TextPanel的程度。如果你想将它开发成一个更复杂的组件,那么我可能建议将初始对象实例化移动到TextPanel本身,就像你通过定义和调度其他自定义事件,以及拥有主应用程序和兄弟组件一样。通过textPanel.addEventListener(或类似于MXML内联)或textPanel.myObject.addEventListener监听组件或可绑定对象上的事件通知,具体取决于哪些是合适的。

答案 1 :(得分:1)

你在这里所做的是mediator pattern的一种实现,这是一种完全可以接受的做事方式,在我看来,可能是你正在寻找的“最佳实践”,因为您正在使用的组件并不直接相互依赖 - 它们只是分派事件并让其他人处理“更高级别”的功能。

执行此操作的另一种方法是dependency injection,您可以在其中为组件提供相互引用,并让它们直接进行通信。这样你使组件彼此依赖(或者可能不是彼此完全相同,但实现相同接口的任何东西),但你不必编写任何中介代码。在这里,与中介模式相反,我所指的“更高级别”功能实际上是组件本身而不是其他人(中介者)的责任。