[Flex]AdvancED Flex 3中文翻译(三)
在例子中添加一些更真实和复杂的东西
前面的假设意味着支持五种可能替代model接口实现了单一view。为了实现这一目标,你需要抽象出一种model数据结构,不管选择哪一种数据源,在程序中都有这个结构。通常情况下,建立一个这样的结构是一个面向对象(OO)的model和可能用代理的远程数据源。这样做不仅仅是改变model,使那个基础MVC能更好的扩展和松耦合,也能确保在以后更复杂的view,controller,services和model在全面的互动时得到好的处理。
为了实现这一目标,我们需要做以下事情:
■用面向对象(OO)的形式创建一个有代表性的model。
■创建一个代理model,无论任何时候都能访问和操作本地或远程的。
■总结内外部的数据访问services。
■创建一个所有服务的注册表,记录Flex与内部、外部数据源的所有应用程序接口。
■提供一种机制来查询服务注册表和调用一个服务。
■在用户操作或系统事件发生时,创建一个命令来调用服务及调用命令。
■建立一个机制,让model和view能互发消息。
在复杂的情况下,我们还需要做一些额外的事情:
■在应用程序中创建一种松散耦合的消息传递机制,这是对现有Flex消息机制的一种扩充。
■创建一个能注册、取回model的model注册表。
■允许在整个应用程序中定义model,尤其是CRUD应用程序。
■在多个Flex应用程序和多个存取控制层中共享数据应创建一个用命名空间分隔的model注册表
■创建一个能注册、取回command的command注册表。
如果你被上面说的这些东西吓到了,请不要担心。我会一步一步教你每一个步骤,详细地讲清楚,尽快将所有的都讲明白。此外,所有这些概念已经汇总到了一个叫Fireclay的框架中,它可以很方便的使用在你的应用程序中。Fireclay放在Google Code主机上,地址是:http://code.google.com/p/fireclay/
让我们先学习进一步的原理和步骤,然后深入,让它变得更清楚和更有效的。我们首先讨论model有不同的数据源,但不久我们将精力集中在抽象服务,command、proxy和event,这能方便所有类型的model操作和controller相互作用。
在较高的水平,我们通常会有三个主要的部分:view、controller、model,另外附加二个部分:service、event。view是一些组件,通常会调用一些辅助的和公共的一些方法完成一些过渡和效果。model能在代理的帮助下得到本地或远程的复杂的抽象数据。controller查询事件消息和通知帮助event间接执行command通过事件侦听去执行一个service或执行业务逻辑。所有主张支持松散耦合和事件驱动架构。我也建议你积极避开一些想法,这里列出一些反模式:
■频繁的使用数据绑定是不好的。绑定是基于事件模式的,过多的绑定会导致创建过多的事件并没有使用。通常你只会得到model元素的改变的属性值。
■Cairngorm提倡使用单例的model,这是多余的,并且会降低性能。Cairngorm是一个用得比较广泛的开源的Flex应用程序开发框架,我们在后面的章节中讲到它。
■使用Front Controller,在Flex应用程序中,一般流行的请求(request)-响应(response)的web应用程序方式是多余的。
■使用单例的情况下,注册实例或注册event实例是没有必要的,因为这样会限制程序的扩展和单元测试。
我们将讨论一些反模式(一些被推荐的架构),下一节我们会讲得更详细。在此之前我们来看一下我们的新的MVC架构(1-2)

model以面向对象(OO)形式表现
ActionScript 3 (AS3) 是一个面向对象的语言,所以我们将以对象的形式表现model。在我们的例子中,将建立一个MedalWinner对象,它的如下属性:ThreeLetterCode、Name、 GoldMedalCount、SilverMedalCount和BronzeMedalCount。我们创建一个MedalTally类,包含多个MedalWinner对象,我们利用对象的属性,为属性命一些好记的名字,以便于我们能更容易理解model中的单个元素和它们的行为。在远程调用过程情况下,特别是远程调用的语言也是面向对象的(如JAVA),这些相同的对象能够被中间件序列化和反序列化。这些对象往往是调用数据转换对象(DTOs)。DTOs支持多个应用程序一起调用。如果你有不熟悉的概念,可以到以下网站了解:
■Patterns of Enterprise Application Architecture:http://www.martinfowler.com/eaaCatalog/dataTransferObject.html
■Core J2EE Patterns—Transfer Object:http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html
下面的代码是用上面的例子的model建立一个对象,源代码清单中MedalTally对象并没有包含MedalWinners对象,对MedalTally对象来说要包含什么并没有严格的限制。如果确实需要,可以包含一些基于松耦合配置数组。
MedalWinner.as定义了一个MedalWinner类的属性和操作。
- package com.riarevolution.advancedflex3.examples.athens2004.model{
- public class MedalWinner {
- public function MedalWinner() {
- super();
- }
- private var _threeLetterCode:String;
- private var _name:String;
- private var _goldMedalCount:int;
- private var _silverMedalCount:int;
- private var _bronzeMedalCount:int;
- /**
- * threeLetterCode uniquely identifies a medal-winning country
- */
- public function get threeLetterCode():String {
- return _threeLetterCode;
- }
- /**
- * @private
- */
- public function set threeLetterCode(value:String):void {
- _threeLetterCode=value;
- }
- /**
- * The medal-winning country name
- * thats maps 1 to 1 with the threeLetterCode
- */
- public function get name():String {
- return _name;
- }
- /**
- * @private
- */
- public function set name(value:String):void {
- _name=value;
- }
- /**
- * goldMedalCount is the total number of
- * gold medals won by the medal-winning country
- */
- public function get goldMedalCount():int {
- return _goldMedalCount;
- }
- /**
- * @private
- */
- public function set goldMedalCount(value:int):void {
- _goldMedalCount=value;
- }
- /**
- * silverMedalCount is the total number of
- * silver medals won by the medal-winning country
- */
- public function get silverMedalCount():int {
- return _silverMedalCount;
- }
- /**
- * @private
- */
- public function set silverMedalCount(value:int):void {
- _silverMedalCount=value;
- }
- /**
- 13
- LEVERAGING ARCHITECTURAL AND DESIGN PATTERNS
- * bronzeMedalCount is the total number of
- * bronze medals won by the medal-winning country
- */
- public function get bronzeMedalCount():int {
- return _bronzeMedalCount;
- }
- /**
- * @private
- */
- public function set bronzeMedalCount(value:int):void {
- _bronzeMedalCount=value;
- }
- }
- }
MedalTally.as包含了一个MedalWinner数组:
- package com.riarevolution.advancedflex3.examples.athens2004.model{
- public class MedalTally {
- public function MedalTally() {
- super();
- }
- private var _medalWinners:Array;
- /**
- * medalWinners is the collection of winners.
- * Medal count for each type of medal is
- * a property of the MedalWinner class.
- */
- public function get medalWinners():Array {
- return _medalWinners;
- }
- /**
- * @private
- */
- public function set medalWinners(value:Array):void {
- _medalWinners=value;
- }
- }
- }
下面,我们用UML图来描述MedalWinner类和MedalTally类(看1-3):

用面向对象的方式表示model,不会去操作mdoel里的结果集、数据集或原始数据类型。因此可以减少格式之间marshalling和unmarshalling的开销。
在我们的例子中,这个model比较简单。在实际中,model元素之间有复杂的、相互依赖的关系。例如,我们的示例应用程序可能需要更深入,需要金牌获得者的记录。也就是说,您可以选择MedalWinner (奖牌得主的国家)和所有中获得了奖牌的运动员的名单, 对于每个项目中,奖牌得主在赢得了一枚奖牌,你可以列出事件、奖牌类型、哪个运动员赢得了奖牌。例如,在2004年雅典奥运会中“田径”项目中获得金牌的美国人,加特林(运动员)在比赛中赢得男子100米比赛冠军;数据相关的事件,如在加特林完成男子100米比赛用了9.85秒,还可以储存和引用。有了这样的详细和参照的数据,将有可能查询的运动员,比赛,体育,赢得国家,度量范围和奖牌类型。因此,要把握对象的数据之间的相互关系需要准确的结果集。现在,如果数据存储为同一组对象中,处理这些关系,并不难。然而这种情况是很少的。更多的往往不是关系型数据库或表格的形式。这就提出了挑战:它们的映射对象的对应关系,这就是俗称对象关系映射(ORM)。如果你从services获得数据,应该以结果集的关系形式。
一个Flex应用程序中的数据可以以下方式之一:
■从一台远程服务器提取数据,以Flash Player序列化对象形式。
■从远程获得想要的数据集(它们是像HTTPService, WebService这样一些或其它的远程服务)
当对象是系列化的,我们并不真正关心ORM的问题。唯一的一次发挥作用是当的Flex应用程序试图工作在持久层。举例来说,JPA或Hibernate在JAVA中。这种情况下, Hibernate的适配器数据服务通常需要应用。有商业和开放源码的Hibernate的数据服务。一个dsadapters项目BlazeDS (http://code.google.com/p/dsadapters/),能得到自定义适配器和工厂。在第7章将涉及BlazeDS。
因此,当我们得到的是记录集而不是对象时,ORM会出现问题,我们需要协调它与应用程序对象。当记录集没有告诉我们对象的任何的类型时,我们什么都不能做除非有个程序对象的映射图。然而,如果我们能找到潜在的对象的类型,例如:如果我们已经得到了SQL命令获取的数据和元数据或从网络服务器返回的强类型数据,我们能试着得到这些对象的映射图。LifeCycle Data Services(Adobe公司一个比BlazeDS更强大的商业数据服务器)把SQL适配器作为数据管理服务的一部份, dsadapters项目有利用SQL和网络服务的少许适配器和客户端库。为了将重点放在MVC和架构、设计上,我们将不会在Flex应用程序里讨论ORM。
我们更关心的是用一种统一的方式去操作多个model,包括本地的和远程的。一个模式通常能为要求提供一个好的解决方案,也能通过代理模式延时得到model元素。下一节我们将讲解这个。
下节继续!
(转载请注明出处,请勿使用商业用途!)
先顶下…
另外~~上面提到的fireclay的googleCode地址http://code.google.com/p/fireclay/所链接的位置错了..指向的是翻译(二)中简单MVC例子那个图片的地址了…
谢谢提醒,已更正
非常厉害,希望你能继续。