BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

高效率的超大规模Flex开发

| 作者 Ryan Knight 关注 0 他的粉丝 ,译者 曹如进 关注 0 他的粉丝 发布于 2009年11月10日. 估计阅读时间: 22 分钟 | Google、Facebook、Pinterest、阿里、腾讯 等顶尖技术团队的上百个可供参考的架构实例!

Adobe Flex开发与传统的Web开发有很多不同之处。正确的理解和利用这些不同之处,可以帮助我们创建更丰富的用户体验,也可以反过来增加网站的可用性以及浏览和更新速度。Flex还提供了大量的组件和技术库来让Web开发更加轻松——它提供的强大工具要远远超过传统Web 2.0中的异步JavaScript和XML(Ajax)应用。此外,Adobe公司最近发布的Adobe Flash Builder 4 beta(以前叫Adobe Flex Builder)中提供了许多新的和改进的工具,他们可以用来开发大规模的Flex应用程序。Flash Builder 4着重于提高开发人员的生产力以及设计人员和开发人员的工作流。

Flex开发中的关键要素之一是使用模块和运行时共享库(Runtime Shared Libraries,RSLs),这些模块和库可以方便系统不同部分的并行开发以及客户端上高效的内存管理等等。另外一个关键要素是使用Sprint BlazeDS集成,它大大简化了后台不同技术服务器端的开发和集成,如使用Java消息服务(JMS)和Spring安全进行的通信。

以下是Flex开发中的一些关键要素:

  • 利用Flex的不同之处。了解为什么Flex开发与传统Web开发有所不同,并利用那些不同之处让应用程序从中获益。
  • Flex模块。了解Flex模块以及怎样模块化Flex开发和部署。使用Flex模块来解耦项目中的不同层次。
  • 了解反模式和模式。 预先了解正确的应用程序反模式,这样你可以按照正确的架构模式实现优秀的设计。
  • 使用Spring BlazeDS集成项目简化开发。使用Spring BlazeDS 集成项目简化Java服务器集成。
  • 有效地设计。与设计团队紧密合作,充分利用Flex和Adobe Flash的优势。
  • 测试. 预先计划测试。

是什么让Web开发与Flex有所不同?

与传统Web应用程序不同,Flex应用程序开发更像传统的桌面应用开发。例如,整个应用程序会被下载到客户端——这是一个庞大的下载,而且取决于应用程序如何组织。当然,有许多方法可以优化这个过程,例如使用组件库或将工程分解成各个模块。

这套方法与传统的超文本标记语言(Hypertext Markup Language,HTML)编写的应用程序不一样——即使它是用Ajax开发的。一个HTML的Web站点通常可以划分成不同的页面,以使得下载量非常小。并且即使使用Ajax,下载量还是相对较小,因为大部分Ajax库本身就相对较小。使用这种方法可以让单个页面的下载量比整个应用程序更小。

Flex与传统Web应用程序开发的另外一个不同之处在于,状态主要在客户端上维护。这超出了在Web应用程序上使用Ajax控件,因为后者一般只在Web浏览器上维护少量的客户端状态。而现在,应用程序中的所有状态都在局部变量中进行维护。

如果你还不太熟悉Flex的话,另外一个不同之处可能对于你来说是一个挑战。Flex使用了一个高度的事件驱动编程风格,主要原因是Adobe Flash Player是单线程的,因此任何需要长时间运行的调用都需要注册一个回调函数。单线程对于图形化用户界面(GUI)开发来说是有利的,因为它不存在死锁或者一个线程窃取所有CPU周期,从而保持了GUI的响应。单线程还使得开发更加简单,因为你不需要处理多线程编程。(还记得在Swing中处理线程的噩梦吗?)

Flex中用以处理事件的主要机制是函数指针,或者作为函数参数进行传递的闭包。这些指针可以是用户为了某个异步事件结束时发生的事件或者提醒而注册的。(函数指针对于Java程序员来说很有挑战,因为核心Java语言还不支持闭包。)

Flex模块至关重要

Flex提供了一些选项可以将应用程序划分成模块,包括创建库以及主应用程序的子模块。通过将项目设计成层次化的形式,开发和编译都可以在单个的分支中进行。

模块化Flex项目的主要好处在于,这么做可以优化客户端上下载和启动的时间。应用程序的一小部分可以预先下载到客户端,而剩下的部分可以在后端按需很进行加载。此外,模块还可以被加载和卸载,以减少客户端上的内存占用量。

模块化Flex项目的另一个主要好处是,它可以让开发过程更容易模块化。它允许开发人员在不同的模块和库上进行工作以避免开发团队的死锁发生。

然而构建大型Flex应用程序的一个挑战之处在于,编译过程所花的时间要比大部分程序员熟悉的Java编译时间要慢很多。重新编译一个大型Flex应用程序可以花上好几分钟。想要优化这个过程,你可以创建分离的库并且只编译你当前工作的应用程序部分。

一种方法是采用SWC文件形式的库。SWC是Flex中使用的主要存档格式,它有点类似于Java中的Java存档(JAR)文件。你可以使用SWC档案来完成一些工作:

  • 组件库。 组件库是一个SWC文件,它包含Flex应用程序中使用的类和其他资源。
  • 主题。主题定义了应用程序的观感。它包含主题所需的资源(例如图片文件和字体),以及定义这些资源如何被使用在应用程序中的层叠样式表(Cascading Style Sheet,CSS) 。
  • 资源包。这些都是本地化的属性文件和Adobe ActionScript类集。

有两种方法可以在项目中添加SWC文件:要么静态地连接它们,这种情况下它们会编译进你的项目;要么把它们当做运行时共享库(RSL,Runtime Shared Library )来使用。使用多个RSL的好处在于它们可以被分开下载和缓存到客户端上。此外,如果客户端有多个模块的话,它们还可以共享同样的RSL。

你还可以将主应用程序进行模块化。一种方式是采用Flex模块;另一种是使用子应用程序。子应用程序的好处在于它们独立于主应用程序进行开发和测试。

注意当编译模块和库时,Flex并不像Java一样层次地遍历整个树。相反它只编译链接到主应用程序中的部分。这种方式会使得模块和库的开发非常微妙,因为你可能注意不到某个文件被链入了。当进行库开发的时候,有必要定义哪些文件会被包含。

库具有相对直接的可被利用的优势。本质上你是向Flex模块管理器传递了想要加载模块的URL。

    protected function getModuleFromServer(url:String, onSuccess:Function) :void
    {
       var module:IModuleInfo = ModuleManager.getModule(url);
           module.addEventListener(ModuleEvent.READY, loadModuleSuccessHandler);
            module.load();
    }

    public function loadModuleSuccessHandler(moduleEvent:ModuleEvent) :void {
        var module:IModuleInfo = moduleEvent.module;
	  .... handle initializing the module
    }

像这样进行模块加载的有趣之处在于你可以指定另一个URL来加载这个模块——例如,在某个故障情况下,客户端丢失了与主服务器的连接。这时客户端可以继续从另外一个URL中加载模块,以维护重要的业务功能。

让应用程序轻松地开发和测试

通过适当地激活View栈(Stack),你可以用单个URL轻松地访问应用程序的任何点——这一功能拥有超越单纯可用性上的优势。除此之外它还使得应用程序上的工作变得很轻松。一个常见的错误发生在你改动部分应用程序,而这个应用程序需要在好几个屏幕和样式中进行导航。如果你不得不为每一处改动而手工进行导航时,这个过程将非常耗时。取而代之,我们可以使用一个固定的URL来访问应用程序的不同部分,这将大大减轻开发中的痛苦并且加速整个过程。相同的模式同样可以让应用程序变得很容易测试,因为应用程序单个部分可以通过URL来访问和测试。

在Flex中,有两种方法可以将视图栈构建到应用程序中。一种方法是使用状态(states),而另一种方法则是使用一个ViewStack组件(ViewStack.mxml)。视图栈只是用来显示对象的栈:这些对象可以是一个包装简单的表格或是一个复杂组件的画布(canvas )。使用视图栈的好处在于你可以通过在代码中设置当前的子组件来轻松的操作它们。例如 myViewStack.selectedChild=accountInfo 将会设置视图栈去显示accoutInfo视图。这个功能可以让你在测试和开发中轻松地操作视图栈。

客户端架构:反模式

在软件编程中,会有一个通用的范式来定义软件开发中的反模式和模式。模式是解决常见问题的重复解决方案;反模式则是不熟悉语言的程序员最会发生的常见错误。定义好Flex中的模式和反模式后,我将会展示一些新手Flex程序员常犯的错误,然后再展示一些Flex编程开发的最佳实践。

这些实践可以帮助项目在增长为大规模的过程中,避免常见的错误。第一个通用的反模式是将所有的MXML视图放在根包中。这么做的好处不是很明显,因为你可以将MXML文件放入到包中,并且通过它们的名字空间(由于实际的包的名字可能没有在文件中指定)进行引用。其实MXML文件是根据其所在的目录结构来放入包当中的。因此将MXML文件放入到根包中等价于不将它们放入任何包中,这样做会使一个大型项目变得一团糟。

举一个例子,Flex商店示例不仅将主应用程序文件放入到根包中,还将主页,商品页和支持页(HomeView.mxml, ProductsView.mxml, SupportView..mxml)都放入根包中。这个过程和把所有根目录中的视图包放入一个Java包中比较类似。

开发人员在创建第一个应用程序时常常会碰到一个问题:那就是如何用视图来捆绑住应用程序模型。一个通用的反模式是在类之间传递模型或者在调用视图前设置模型。反模式的一个例子——也来自于Flex商店——即在主应用程序中将目录传递进ProductsView。

<ProductsView id="pView" label="Products" catalog="{catalog}" 

这段代码在小的例子中可以正常工作,但是随着应用程序逐渐变大,它会带来一些问题,如层之间的紧耦合,以及很难开发和测试。另外一个问题是当同样的数据需要在应用程序不同部分显示时,这些数据需要分开地传递给每一个组件。首先,这看起来似乎不是一个问题,但是试想下如果尝试模拟每一个传递和使用数据的实例,结果会怎样。

客户端架构:推荐模式

多年来众多的Flex架构和框架已经被开发出来。最有前景的一种方法使用了一个像Swiz一样的轻量级依赖注入框架,并用它来划分项目结构。你可以在Swiz中定义类似于Spring中的应用程序bean,并将它们注入到应用程序中的不同部分。一个典型的应用程序框架会包含一个中心类,这个类会定义服务怎样组合在一起——例如,ClientBeans.mxml 类为应用程序声明了通用的模型和控制器:

<model:StoreModel id=”storeModel” />

然后View类连接上控制器:

[Autowire(bean="storeModel")] 
[Bindable] 
public var storeModel: StoreModel; 

对于控制器和其他通用组件,你也可以这么做。用这种方式组织项目结构有一些优势。一个优势在于它可以让模拟服务轻松地植入控制器,以促进开发和测试。另外一个优势在于它能够除去和客户端架构不同层之间的耦合性。

一个精心设计的主视图状态有助于实现前面提到的可用性和可测试性目标。视图栈的思想是让应用程序中的任何视图可以通过单个URL进行访问。除此之外,视图栈的参数需用通过通用控制器传入,这个通用控制器能够让你在应用程序中各个地方使用通用的URL和必要的参数来访问期望的视图。

一个Flex架构示例:重构View Store

作为架构的一个示例,让我们先看看怎样将http://www.adobe.com/devnet/flex/samples/flex_store/ 上的Flex Sotre的例子进行重构。

首先,将主源代码移动到子目录中。在这个例子中,我将所有的资源,产品视图,以及样例目录移动到了flexstore/src/flex中并将其作为源代码主目录。我还把所有的MXML和CSS文件移动到了这个目录中。

接下去,将三个主视图类移动到视图文件夹中。在src/flex目录下创建一个com/anvilflex/view目录。将 HomeView.mxml,ProductsView.mxml以及SupportView.mxml文件放入到这个目录中。为此,你必须对 flexstore.mxml做出如下改动:

  • 在<mx:Application>标签中加入xmlns:view="com.anvilflex.view.*" 。
  • 将视图变为使用<view>标签(因此<HomeView>将变成<view:HomeView ... />)。

将Product.as类移动到分开的域文件夹中——com/anvilflex/view。为此,你必须修复Product类的import 语句,并删除Product单词的最后一个字母。接下去,按住Ctrl-空格键来使用自动完成功能,它同样也可以为Product类加入正确的 import语句。

最后,引入ProductControl来管理产品页面和结算间的过渡。

使用Spring BlazeDS集成简化Java开发

Spring BlazeDS集成项目大大简化了与客户端交互的Java服务端代码开发。在最新发布的项目中,团队成员可以实现核心的配置文件,如web.xml以及Flex服务配置文件。接下去,团队人员需要简单地了解一下如何在他们的类中增添适当的标注来将它们作为服务展现给BlazeDS。举个简单的例子,你可以将Product服务类展现为一个远程服务:

	@Service("productService")
	@RemotingDestination(channels={"my-amf"})
	public class ProductDAO {

	@Autowired
	public ProductDAO() {
		//... initialize the ProductDao class
	}

	@RemotingInclude
	public Product findProductName(int id) {
		Product product = database.findProduct(id);
		return product.name;
	}

在这个例子中,我将ProductDAO类声明为了远程服务,它可以通过使用productService进行调用。单个方法可以使用 @RemotingInclude将其展现为远程方法。其实这些方法都会作为远程服务展示给BlazeDS,其中Flex可以通过远程对象调用远程服务。

与图形设计团队一起工作

刚开始的Flex项目中一个常见的问题是,确保图形设计团队了解Flex中可以做什么。Flex为很多有趣的设计提供了可能性:图形设计团队需要了解Flex中可以做什么,以及Flex怎样来表示一个基础设计转变。

通常情况下,碰到的问题是,图形设计团队用一些像Adobe Photoshop的工具创建了一个模拟。尽管设计看起来非常好,但是它与工作中的应用程序还相距甚远。整个设计将不得不削减并且颜色和字体都得与应用程序的CSS相匹配。根据设计的复杂度,自定义的Flex组件也需要被创建。这些组件可能是需要自定义皮肤的按钮,也可能是定义了一系列新功能集合的组件。困难之处在于设计和实现之间变得极其耗时,设计人员需要搞清楚什么是可能的并从设计中实现这些变化。每一次迭代都会变得更加复杂。

幸运地是,Adobe已经引入了一个新的工具来改进这个过程,这个工具就是Flash Catalyst。它可以让类似Photoshop这样工具产生的艺术品能够轻松地转变为可用的原型。它还可以创建一个原型的GUI并最终应用到应用程序中。通过使用此工具,设计人员可以更快地遍历他们的设计,从而使该组织能更有效地调整设计,以满足其要求。

单元及功能测试

Flex开发中有两种主要的方法来测试一个应用程序。第一个是使用funit或者fluint的功能测试。这个方法可以进行服务以及控制器的测试。第二个方法是功能测试,它可以测试与GUI间的实际交互。功能测试可以使用像Mercury一样的商业工具,或者像FlexMoneky一样的开源工具。

两种类型测试的关键是要在松耦合层创建可以独立测试的代码。例如可以通过将默认捆绑改变为使用模拟服务,来轻松地修改服务。

总结

使用Spring BlazeDS集成的Flex为大规模企业应用程序提供了一系列卓越的技术。开发人员的挑战在于设计模块化,易调试,可扩展的架构。这里的可扩展,我指的不仅仅是软件,还包括开发过程。解决这些挑战可以帮助项目成功,并为组织带来一个更高的投资回报率。

查看英文原文:Super-sized Flex Development—Without the Extra Calories


译者介绍:曹如进,计算机软件与理论专业硕士研究生,主要研究方向包括算法设计与分析,语义网。目前对函数式编程语言,富客户端开发比较感兴趣。InfoQ中文站内容团队,尤其是架构、SOA和Ruby社区需要您的参与,有意者请邮件至editors【AT】cn.infoq.com

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

"因此将MXML文件放入到根包中等价于不将它们放入任何包中,如果不这么做,一个大型项目会变得一团糟。"貌似翻译有问题。 by Jiamin Liu

"因此将MXML文件放入到根包中等价于不将它们放入任何包中,如果不这么做,一个大型项目会变得一团糟。"
文中这句翻译貌似意思跟原文刚好相反了,应该是“如果这样做”才对吧?

Re: by 曹 如进

感谢指教,我的疏忽。修改为:
“因此将MXML文件放入到根包中等价于不将它们放入任何包中,这么做的话会使一个大型项目变得一团糟。”

我这里有两个问题 by Qin Robin

AS3(FLEX)项目客户端基本有:
-于UI展示交互相关的扩展类,内部包括展示,交互animation的函数,自定义事件。
-负责和后台交互的数据通信类。
-定制化代码,包括声明的instance(实现不同), styling,data entry urls, customized event binding.

AVM2平台并没有给出
-用户多线程来处理计算和于服务端的交互。
-数据量大时候的计算调度。(假死)
-较复杂阻塞等待机制。

基于RIA Flex Flash 平台开发的进销存企业信息管理系统开发经验 by tangu soft

基于RIA Flex Flash 平台开发的进销存企业信息管理系统开发经验

(欢迎转载,转载请注明作者,尊重版权)

作者www.tangusoft.com



关键字: RIA Flex 应用成功案例 实际项目


四,基于Flex的进销存系统演示地址


www.tangusoft.com/Demo/


一.中小企业进销存系统和运行平台以及技术架构



1. 中小企业进销存系统特点:

a. 目标客户

零售批发中小企业,企业规模人数500人以下,销售额1500万元以下。

b. 数据操作频繁

每天频繁操作销售和采购以及仓库出入库,经常需要查看企业基本信息,包括商品信息,客户供应商信息,应收应付。并且需要快捷的操作系统。

c.存储数据量有限

商品信息大概5000条,客户供应商大概1000,

每天单据信息大概50条,每年单据信息大概20000条

d.并发操作用户数量固定

销售员,采购员,经理,财务,大概20人左右。

e. 用户使用地点不同

需要直接方便浏览器访问系统

f. 客户浏览器处理功能强大

目前客户电脑普遍内存1G, 处理器 双核2.0 以上

g.中小企业普遍软件预算不高

同时也尽量避免盗版软件引起的法律诉讼和纠纷。



2. 运行平台和系统架构

根据中小企业进销存系统的众多特点,同时考虑技术成熟度和新技术风险,我们决定采取以下运行平台和系统架构

运行平台 Linux Apache Tomcat Mysql

系统架构

表现层Flex 3

数据处理和控制层Blazds + Spring + Ibatis



Flex/Flash 具有以下优点

客户端 界面友好,数据表现能力强大,处理能力强大,有一定的缓存数量的能力,减少服务器请求次数,节省不必要的网络传输。

BlazDS 能够处理并发用户的请求,并且能够压缩数据。

Spring 声明性的代码配置,减少系统维护工作量

Ibatis 减少实际编码,考虑以后支持多种商业数据库



运行平台免费,企业零预算。



二,框架和代码生成器





1. 选择成熟的Flex 框架



cairngorm 和 pure MVC 是目前成熟的open source 框架。

基于Adobe 支持和维护cairngorm,所以采用cairngorm

同时cairngorm 对view 表现层 和 control 控制层 的 隔离和耦合没有成熟的解决方案,开发过程我们曾经使用ViewControllerHelper ,用addListener监听器监听event 事件的执行,实际过程发现代码维护成本太高,遂中途放弃。

最后我们同时引进universal mind cairngorm作为补充辅助框架。

2. Ibatis 代码生成器

选择Abator





三,解决方案

1. 客户端尽可能使用单例模式

减少不必要的客户端内存开销

2. 适度利用客户端缓存

对于商品以及客户供应商, Flex 缓存这些数据,各模块共享数据。

3. 尽可能的采用lazy load 惰性载入数据

很多Flex 系统采用初始化时候一次性载入系统所需要数据,结果导致延长用户登录时间,用户体验非常的差。

4. 不要过度依赖客户端处理能力

特别是大数据排序或者处理请求大数据能力的时候,flex 很容易导致浏览器停顿和不响应。请把大数据排序放在Java或者数据库端,适度的分页分段向服务器请求数据。

5. 最大有效的利用Flex 3新的类库。

减少开发工作量。

例如利用arraycollection 内置的filerfunction 进行查找数据。

6. 定制开发一些特有的控件

带合计栏的datagrid

能模糊查询的combobox

7.报表开发

使用成熟的jasper report 框架。

8. 用户权限的开发

动态创建用户所能操作的模块,而不是简单控制模块的可见和不可见属性

9. 减少生成swf 大小

使用runtime shared library 编译swf

10. 开发模块组件化

判断标准是没有出现冗余重复模块代,application mxml 文件代码简洁

11. 模块之间的数据和方法调用



A模块引用B模块的数据d和方法f,避免简单的调用B.d 和 B.f

需要采用数据和方法的传递,以免多层次的模块数据和方法调用导致代码的复杂。

12 使用resource bundle

标签和文本以及提示从resource 文件读取。

Re:还是有点生硬啊! by li wenzhi

应该是:
因此,如果将所有MXML文件都直接放入src中而没有按类包组织,这么做的话。。。。

看来还是有点开发基础翻译起来容易些啊。

单元测试 by fudong cui

应该是原文的一点小错误,在“单元及功能测试”一节中,“第一个是使用funit或者fluint的功能测试”应该是“单元测试”吧?

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

6 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT