Prototypes for Flash/Flex

Prototype 提供了实现的最小功能,用于验证可行性和作为参考。

使用Parsley构建Flex Application (翻译)

原文链接 http://coenraets.org/blog/2009/07/building-a-flex-application-with-the-parsley-framework/

在最近研究了Swiz和SprintActionScript(1,2,3)之后,我决定再试用一下Parsley framework,创建Parsley版本的inSync,这是一个简单的管理联系人的应用,我经常用这个作为demo演示Flex和Adobe AIR的特性和技巧

Parsley首先是一个依赖注入的framework。它还提供了一种有趣的消息机制作为基础。依赖注入就不多说了,之前Swiz和Spring ActionScript的文章中有一些背景资料和很多细节作为参考。

如果只想运行程序或者看看源代码,链接在这:程序源代码

配置 Object

Parsley让你有多种方式配置核心的objects(其他的组件依赖于这些对象),使用MXML(像Swiz),使用XML(像Spring ActionScript)或者ActionScript。或者各种方式的组合。甚至可以扩展framework,创造你自己的配置机制

就inSyc而言,我选择了MXML的方式(Config.mxml),如下

 
<?xml version="1.0" encoding="utf-8"?>
<Object xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:services="insync.parsley.services.*">
 
    <mx:RemoteObject
            id="contactRO"
            destination="contacts"
            endpoint="http://localhost:8400/samples/messagebroker/amf"
            showBusyCursor="true" />
 
    <services:ContactService />
 
</Object>

注,在实际项目中,你并不应该hardcode service的endpoint。使用XML在外部(更外了)来配置endpoint。这里有更多相关的讨论

初始化Framework

你选择了那种类型的配置方式,就通过与之对应的ContextBuilder来初始化framework。下面是inSync的Main文件。我让Parsley在preinitialize event中初始化。

 
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:views="insync.parsley.views.*"
        paddingTop="0" paddingLeft="0" paddingRight="0" paddingBottom="0"
        preinitialize="FlexContextBuilder.build(Config)">
 
        <mx:Script>
                <![CDATA[
                        import org.spicefactory.parsley.flex.FlexContextBuilder;
                ]]>
        </mx:Script>
 
        <mx:Style source="styles.css" />
 
        <views:MainView />
 
</mx:Application>

依赖注入

Parsley支持构造函数注入,方法注入和属性注入(指定type和指定id)

下面的例子(ContactForm.mxml),framwork将注入IContactService的具体实现,实例是由Config.mxml创建的ContactService,通过指定type注入。针对接口编程,让view对IContactService的具体实现解耦。

注:Parsley并不强制你使用特定的设计模式。就这个简单的sample而言,我直接把Service注入到view。使用接口一定程度的做到了解耦,你当然还可以使用其他的模式(比如Presentation Model)来架构更高层的抽象。Parsley的依赖注入和消息机制让应用这些模式更加容易。

 
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
        addedToStage="dispatchEvent(new Event('configureIOC', true))">
 
        <mx:Script>
                <![CDATA[
 
                import insync.parsley.model.Contact;
                import insync.parsley.services.IContactService;
 
                [Inject]
                public var service:IContactService;
 
                [Bindable]
                public var contact:Contact;
 
                private function save():void
                {
                        contact.firstName = firstName.text;
                        contact.lastName = lastName.text;
                        contact.email = email.text;
                        service.save(contact);
                }
 
                private function remove():void
                {
                        service.remove(contact);
                }
 
                ]]>
        </mx:Script>
 
        <mx:Form>
                <mx:FormItem label="Id">
                        <mx:TextInput text="{contact.id}" enabled="false"/>
                </mx:FormItem>
                <mx:FormItem label="First Name">
                        <mx:TextInput id="firstName" text="{contact.firstName}"/>
                </mx:FormItem>
                <mx:FormItem label="Last Name">
                        <mx:TextInput id="lastName" text="{contact.lastName}"/>
                </mx:FormItem>
                <mx:FormItem label="Email">
                        <mx:TextInput id="email" text="{contact.email}"/>
                </mx:FormItem>
        </mx:Form>
 
        <mx:HBox left="12" bottom="12">
                <mx:Button label="Save" click="save()"/>
                <mx:Button label="Delete" click="remove()"/>
        </mx:HBox>
 
</mx:Canvas>

注意到,view为了得到注入进来依赖对象,在被添加到stage的时候,view必须dispatch "configureIOC"事件

消息

Parsley提供通用的消息机制,允许在对象之间松耦合,灵活和易用的传递消息:

event的dispatcher和handler不知道彼此
event的dispatcher和handler和framework之间也是松耦合的,通过Flex的方式dispatch事件

我们来看一下inSync中Search这一块儿。

ToolBar中有一个TextInput让用户输入查找条件
ContactList在DataGrid中显示查到的结果

Toolbar如下(去掉了逻辑不相关的代码以清晰)

 
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%"
        addedToStage="dispatchEvent(new Event('configureIOC', true))">
 
        <mx:Metadata>
                [ManagedEvents("search")]
        </mx:Metadata>
 
        <mx:Script>
                <![CDATA[
                        import insync.parsley.events.SearchEvent;
                ]]>
        </mx:Script>
 
        <mx:Label text="Search:" top="18" right="164"/>
 
        <mx:TextInput id="searchBox" right="0" top="16"
                change="dispatchEvent(new SearchEvent(SearchEvent.SEARCH, searchBox.text))"/>
 
</mx:Canvas>

注意看input的内容change的时候dispatch SearchEvent事件。

使用ManagedEvents MetaData定义这些个event是被framework管理的,意思说framework将保证到时候这些事件会被对其感兴趣的部分正确的收到。

怎么注册被framework管理的event的listener呢?我们在给function加注[MessageHandler]Metadata,这个函数就自动变成了对应事件的handler,不管显示列表结构,或者事件冒泡与否。

ContactList如下(去掉了不相关的代码)

 
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"
        addedToStage="dispatchEvent(new Event('configureIOC', true))">
 
        <mx:Script>
                <![CDATA[
 
                        import mx.controls.Alert;
                        import mx.collections.ArrayCollection;
                        import mx.rpc.events.FaultEvent;
                        import mx.rpc.AsyncToken;
                        import mx.rpc.AsyncResponder;
                        import mx.rpc.events.ResultEvent;
 
                        import insync.parsley.events.SearchEvent;
                        import insync.parsley.services.IContactService;                 
 
                        [Inject]
                        [Bindable]
                        public var service:IContactService;
 
                        [Bindable]
                        public var contacts:ArrayCollection;
 
                        [MessageHandler]
                        public function searchHanlder(event:SearchEvent):void
                        {
                                service.getContactsByName(searchStr).addResponder(new AsyncResponder(getContacts_result, faultHandler));
                        }
 
                        private function getContacts_result(event:ResultEvent, token:AsyncToken):void
                        {
                                contacts = event.result as ArrayCollection;
                        }       
 
                        private function faultHandler(event:FaultEvent):void
                        {
                                Alert.show(event.fault.faultString);
                        }               
 
                ]]>
        </mx:Script>
 
        <mx:DataGrid id="dg" dataProvider="{contacts}" width="100%" top="0" left="0" right="0" bottom="0"/>
 
</mx:Canvas>

单单使用[MessageHandler] ,在Application范围,每次和handler参数相同类型的事件被dispatch的时候,handler都会被调用。为了更好的控制handler该被调用,可以指定selector为某些特定的event type。比如MainView.mxml,contactDeleted函数被注册为只监听ContactEvent.DELETED事件的handler,如下:

 
[MessageHandler(selector="contactDeleted")]
public function contactDeletedHandler(event:ContactEvent):void
{
}

Parsley还有更多的消息使用方法。比如可以用[MessageBinding]来bind一个对象的属性到一个事件的属性:

 
[MessageBinding(messageProperty="result",type=" mx.rpc.events.ResultEvent")]
public var contacts:ArrayCollection;

实例代码的安装调试

1,下载整个Project
2,导入到Flash Builder
3,运行application。这个application默认使用MockService(ContactServiceMock),所以不需要后台

如果需要远端service而不是MockService

1,替换<services:ContactServiceMock/>为<services:ContactServiceRemote/>
2,安装BlazeDS turnkey server
3,下载insync-parsley-java.zip 后解压到本地
4,复制classes/insync 到blazeds/tomcat/webapps/samples/WEB-INF/classes/insync
5,添加destination到blazeds/tomcat/webapps/samples/WEB-INF/flex/remoting-config.xml

 
<destination id="contacts">
        <properties>
            <source>insync.dao.ContactDAO</source>
            <scope>application</scope>
        </properties>
</destination>

6,复制insync/sampledb/insync 到blazeds/sampledb/insync
7,编辑blazeds/sampledb下的server.properties 按照下面的方式把inSync的database添加到启动项中
8,启动database (用startdb)
9,启动blazeDS
10,运行Application

posted on 2010-05-22 09:05  Andy Shang  阅读(1957)  评论(0编辑  收藏  举报

导航