Cairngorm文档--简单示例程序解读

简单示例程序解读

A Simple Sample Application Explained

原文地址:

http://opensource.adobe.com/wiki/display/cairngorm/SimpleSampleApplicationExplained

译稿最后修改时间:2010-6-1 12:36

 

介绍

此文仅是烟水晶框架构建应用的一个小小示范。

 

展示的例子是MAX2009会议上的“用Flex框架构建数据驱动型应用程序”主题演示的一部分。客户端代码示例是以烟水晶架构为基础构建和扩展的。关于此次演示的更多信息请查看克里斯多夫克雷茨 的博客。

 

这里查看客户端代码

服务端组件:下载 安装介绍

为了运行示例程序,服务器端组件必须安装。但是对于理解本教程并非必须。

 

这个示例使用了欧芹程序框架,然而本教程不会深入探讨欧芹框架的特性而是代以烟水晶框架的指导原则的特点。然而,此处概念上的实践可以应用于当前Fash平台上各种各样的应用程序框架。

 

包结构

包结构是重要的管理代码的途径。一中一致性的结构能够使得代码内的查找工作更容易进行,而且更容易理解各个不同部分之间的依赖关系。InsyncBasic 应用程序仅展示了烟水晶框架的建构层的代码是如何分离的。Insync代码包的后面,您可以找到下面这些代码包,描述了建构层:

表现层(关注于视觉外观和表现行为)

应用层(关注于表现的协同和架构组件)

域层(仅关注于问题域)

基础层(关注于例如 遥控服务或者UI框架)

 

这些包展示我们推荐的分层架构。

让那个我们从表现层开始深入这些架构层。

 

看,无脚本块的功能

刚开始,打开主程序文件,InsyncBasic.mxml,然后导航到线面显示的这个结构。您注意到的第一个东西是MXML可视组件内的一个没有脚本块的功能。这使得外观关注于尺寸和布局,使得在外观设计改进的时候更易阅读和更改。这是ToolBar组件:

<mx:Script>

    <![CDATA[

        [Inject]

        [Bindable]

        public var model:ToolbarPM;

    ]]>

</mx:Script>

 

<mx:Button

    styleName="contactsAddButton" toolTip="Add Contact"

    click="model.addContact()"/>

 

<mx:Spacer width="100%"/>

 

<mx:Label text="Search:"/>

 

<mx:TextInput id="searchBox"

    change="model.search(searchBox.text)"/>

注意Inject标记。这是欧芹程序框架的部分功能,将ToolbarPM注入Roolbar 视图。

 

进入表现模型

无脚本块内的各种功能被提取到表现模型。每个MXML标记的可视组件拥有各自的表现模型(PM)。表现模型关注于用户和处理用户输入的状态和行为必需的表现数据。而且其与其他的表现模型乃至程序的其他部分完全无关。

 

这就是ToolBarPM,它在客户端组件接受搜索事件之前去掉了用户输入的字符中的左侧和右侧空格

public class ToolbarPM extends EventDispatcher

{

     [MessageDispatcher]

     public var dispatcher:Function;

 

     public function addContact():void

     {

            dispatcher(ContactEvent.newAddContactEvent());

     }

 

     public function search(keywords:String):void

     {

            if (keywords == null)

                    return;

 

            keywords=StringUtil.trim(keywords);

 

            dispatcher(new SearchEvent(keywords));

     }

}

一个表现模型不应该直接依赖一个可视组件;而应该是视图(可视组件)观察表现模型。这条联系在可视组件和它的通信表现模型之间的线路代替了绑定表达式和内联事件处置功能。这是ContactsList可视组件:

<mx:Script>

    <![CDATA[

        import insync.domain.Contact;

 

        [Inject]

        [Bindable]

        public var model:ContactsListPM;

    ]]>

</mx:Script>

 

<mx:DataGrid id="list"

    width="100%" height="100%"

    dataProvider="{ model.contacts.items }" doubleClickEnabled="true"

    itemDoubleClick="model.editContact(Contact(list.selectedItem))">

    <mx:columns>

        <mx:DataGridColumn dataField="firstName"

            headerText="First Name"/>

        <mx:DataGridColumn dataField="lastName"

            headerText="Last Name"/>

        <mx:DataGridColumn dataField="phone"

            headerText="Phone"/>

    </mx:columns>

</mx:DataGrid>

对于这个视图内完全没有逻辑错误处理的途径,真正的逻辑存在于表现模型内,这样更容易进行单元测试。由于异步组件的生命周期和对其他组件的弱依赖性(例如其他可视控件),直接对可视组件进行单元测试要困难的多。一个表现模型也会以将可视组件的APIMXML内可用的UI组件的大量API中抽离出来的方式简化组件。

 

组件之间的协调

一个程序内不同的组件需要协调来为用户提供有用途的特性。当在搜索栏内输入信息是,结果需要出现在下方的联系人列表内。这个行为是与表现关注相分离的,所以布局是能够独立修改的。

InsyncBasic程序内,搜索操作是被ToolBarPM分发的了搜索事件调用的:

public function search(keywords:String):void

{

    if (keywords == null) return;

 

    keywords = StringUtil.trim(keywords);

 

    if (keywords.length > 0)

    {

        dispatcher(new SearchEvent(keywords));

    }

}

Commands内封装操作

搜索事件是在应用层接收处置的,一个Command以调用遥控服务并且将成功返回的结果放入一个域层内的域对象的形式调用RPC操作。

public class SearchContactsCommand

{

 

    [Inject]

    public var contacts:Contacts;

 

    [Inject]

    public var cache:IDataCache;

 

    [Inject]

    public var service:RemoteObject;

 

    public function execute(event:SearchEvent):AsyncToken

    {

        return service.getContactsByName(event.keywords) as AsyncToken;

    }

 

    public function result(items:IList):void

    {

        contacts.addContacts(cache.synchronize(items));

    }      

}

这个Command遵从欧芹的动态Command特性。这个搜索事件的返回是由名为“execute”的方法处置的,而数据结果由名为“result”的方法处置。如果这个示例需要处置额外的错误反馈,指定另外一个名为“error”的方法。这个约定强制声明在欧芹上下文内的动态Command内部。

DynamicCommand type="{ SearchContactsCommand }"/>

也要注意一下IDataCache工具,这是烟水晶集成库的一部分。更多内容详见IDataCache,单击此处。

 

序列操作

Insync这个程序当新的联系人保存后刷新所有视图来显示最新数据。这使用LCDS的数据同步特性很容易处理,然而,在Insync程序内仅使用RPC操作,客户端需要在保存操作返回成功后手工调用搜索方法。这个简单的队列可以由应用层的专用对象来获得,就是RefreshSearchAfterSaveController

public class RefreshSearchAfterSaveController

{

     [MessageDispatcher]

     public var dispatcher:Function;

 

     private var lastSearch:String="";

 

     [MessageHandler(selector="search")]

     public function onSearch(event:SearchEvent):void

     {

            lastSearch=event.keywords;

     }

 

     [CommandResult(selector="save")]

     public function onSaveComplete():void

     {

            dispatcher(new SearchEvent(lastSearch));

     }

}

关于队列的更进一步的需求经常用于例如程序启动或者队列域行为,请查看任务类库。

 

保持小对象

注意前面示例中的小对象。从上面RefrdshSearchAfterSaveController或者下面的Contacts域对象内的真正只有一个责任。其所有方法引用所有的实例属性从而达成了功能的高内聚性。这将保证您的代码简洁,专注和更有弹性的修改。查看单责任原则以获得更多信息。

[Event(name="itemsChange", type="flash.events.Event")]

public class Contacts extends EventDispatcher

{

    public static const ITEMS_CHANGE:String = "itemsChange";

 

    private var _items:IList = new ArrayCollection();

 

    [Bindable("itemsChange")]

    public function get items():IList

    {

        return _items;

    }

 

    public function addContacts(items:IList):void

    {

        _items = items;

        dispatchEvent(new Event(ITEMS_CHANGE));

    }

 

    public function addContact(contact:Contact):int

    {

        var index:int = -1;

        if (items.getItemIndex(contact) == -1)

        {

            items.addItem(contact);

            index = items.length - 1;

        }

        return index;

    }

 

    public function addItemAt(contact:Contact, index:int):void

    {

        items.addItemAt(contact, index);

    }

 

    public function removeContact(contact:Contact):int

    {

        var index:int = items.getItemIndex(contact);

 

        if (index != -1)

        {

            items.removeItemAt(index);

        }

        return index;

    }

 

    public function removeContactAt(index:int):Contact

    {

        return Contact(items.removeItemAt(index));

    }

}

此处就是InsyncBasic的基础示范的终结了。InsyncBasic仅仅展示了一个功能区,处理联系人。InsyncModularExtended 示例程序和教程关于与如何使用烟水晶框架推荐的其他功能区,例如信息传递和开销,以进一步了解烟水晶框架。

 

参考

马汀,R。单责任原则。

http://www.objectmentor.com/resources/articles/srp.pdf of OOD principles.

最后修改日期:星期日 五月 16 06:20:27 PDT 2010

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值