Flex Viewer 解析(三)Flex Viewer架构解析
OK!进入主题,本小节我们一起来探究一下Flex Viewer的庐山真面目! 3.1? Flex Viewer主席团在com.esri.viewer.managers包中,汇集了Flex Viewer中所有的Manager。这些Manager各个肩负重任,他们虽隐身幕后,却是Flex Viewer良好运转的关键,我们不妨称之为主席团成员。 1)???? ConfigManager Flex Viewer通过配置文件来组织数据、功能和UI。ConfigManager的责任是适时读取配置文件,对配置文件进行解析,然后将解析结果分发出去,由其他需要使用配置文件数据的模块接收。 2)???? DataManager Flex Viewer各个部分之间需要共享数据,比如说Widget与Widget之间数据共享。DataManager提供了一种数据共享的方案,任何模块都可以通过DataManager把数据贡献出来,供其它模块使用。 DataManager的关键职责是把共享数据保存在内存中,任何时候都可以从DataManager获取需要的共享数据。 3)???? MapManager Map是GIS应用的基础。MapManager解决了Map的问题。MapManager不是对Map的简单封装,而是提供了所有与Map相关的操作,比如根据配置文件加载地图,放大、缩小这些基本操作,画图,在地图上显示信息框,图层控制等等。如果在某个自定义Widget中,想要画一个多边形,不必new一个DrawTool,发个消息告诉MapManager你想画个多边形即可;如果你想在地图上某个点上显示一些信息,同样发个消息告诉MapManager就行了。MapManager会很友好地帮我们完很多工作,我们只需发个消息知会一声。 4)???? ScriptingManager 预留,尚未使用。 5)???? SecurityManager 预留,尚未使用。 6)???? UIManager Flex Viewer用户体验之所以风格统一,是因为UIManager做了大量的工作。在配置文件中,有如下脚本,UIManager会根据这一信息对UI的样式进行配置。 <style> ??????? ???????<colors> 0xFFFFFF,0x333333,0x101010,0x000000,0xFFD700 </colors> ??????? ???????<alpha>0.8</alpha> </style> 7)???? WidgetManager 顾名思义,WidgetManager是对Widget进行管理的组件。WidgetManager对Widget的管理包括根据配置文件创建Widget信息列表、加载Widget、布局Widget、关闭Widget等。WidgetManager提供四种Widget布局方式:自由布局(float)、水平布局(horizontal)、垂直布局(vertical)和固定布局(fix)。自由布局Widget可以拖动,水平布局、垂直布局和固定布局Widget完全有WidgetManager管理,不可拖动;四种布局方式中,固定布局Widget不可改变窗口大小。 3.2? Flex Viewer松耦合的关键系统耦合度是决定系统灵活性与可维护性的关键。Flex Viewer的松耦合设计是其健壮的关键因素之一。那么,是什么保证了Flex Viewer的松耦合呢? “事件!事件!还是事件!” 事件是Flex Viewer松耦合的关键。在3.1中多次提到了“消息”,物化到Flex Viewer中就是事件。不同的模块通过事件彼此交互、传递数据,保证了各模块之间的松耦合,彼此不必相知,却能紧密合作。ViewerContainer、EventBus、AppEvent组成了Flex Viewer事件机制的基础。当然,Flex Viewer事件机制的基础是Flex的事件机制。 1)???? EventBus 继承自EventDispatcher,使用了单例模式。EventBus是全局的事件派发器,为Flex Viewer中的不同模块之间的交互提供便利。有了EventBus,不同模块之间的交互无需彼此调用对方的方法,只需派发/监听消息即可。 2)???? AppEvent 继承自Event,在Flex Viewer中被用来当做消息和数据的载体,在不同的模块之间传递数据。AppEvent定义了Flex Viewer中需要的所有事件类型,也就是那些公共的字符串常量。通常,系统层面需要添加的事件也都定义在AppEvent中。 3)???? ViewerContainer 继承自Group,使用了单例模式,是Flex Viewer中各个模块的容器。Flex Viewer中调用ViewerContainer最多的三个方法是:addEventListener()、dispatchEvent()、showError()。我们可以在任何需要对某类AppEvent事件进行监听的地方通过addEventListener()方法添加监听,可以在任何需要派发某类AppEvent事件的地方通过dispatchEvent()方法派发事件,可以在任何需要显示Error信息的地方通过showError()方法显示Error信息。如果通读Flex Viewer代码,会发现,AppEvent的监听与派发随处可见。 Flex Viewer松耦合的关键因素还有Widget的设计和实现,这部分内容将在后面的小节涉及,在此按下不表。 至此,我们的讨论涉及到了Flex Viewer中的绝大部分模块,先来看一下Flex Viewer的整体结构,如图3.1所示。图中最下方的Control Widgets和Business Widgets尚未提及,我们将在3.4中涉及这部分内容。 ? ???????? 图 3.1 Flex Viewer整体结构 3.3? 初始化那些事儿在浏览器地址栏输入Flex Viewer的地址,经过短暂等待,当她华丽丽地展现在我们眼前,你是否想过在这短暂的等待中,Flex Viewer都做了哪些事情呢?本小节我们来探讨Flex Viewer初始化那些事儿。注意,我们这里所说的Flex Viewer初始化,不是Flex概念中组件生命周期的初始化部分,而是指Flex Viewer在可以与用户交互之前,所做的准备工作。 ? 图 3.2 Flex Viewer初始化过程 3.2小节中,我们强调通过使用事件,Flex Viewer将各模块之间充分解耦。实际上,事件也伴随着Flex Viewer初始化的整个过程。Flex Viewer的初始化过程如图3.2所示。 1)???? 首先观察一下ConfigManager的构造方法,其中有这样一句代码: ViewerContainer.addEventListener(ViewerContainer.CONTAINER_INITIALIZED,init); 也就是说,ConfigManager实例在构造期间就通过ViewerContainer在EventBus的单例添加了对CONTAINER_INITIALIZED事件的监听,一旦ViewerContainer在别的地方派发了CONTAINER_INITIALIZED事件,ConfigManager将响应该事件,开始读取配置文件、解析配置文件,构造ConfigData数据,最后将ConfigData连同CONFIG_LOADED事件派发出去,见下面代码: ViewerContainer.dispatchEvent(new AppEvent(AppEvent.CONFIG_LOADED,configData)); 2)???? 我们再观察一下UIManager、WidgetManager和MapManager的代码,在各自的初始化代码中,都可以找到下面一句代码,此处不再解释: ViewerContainer.addEventListener(AppEvent.CONFIG_LOADED,config); 3)???? 最后,问题的关键在于CONTAINER_INITIALIZED事件何时何地被派发?我们观察一下ViewerContainer的init()方法,其中有下面这句代码: ViewerContainer.dispatch(ViewerContainer.CONTAINER_INITIALIZED); 而init()方法是ViewerContainer的creationComplete事件的响应方法。也就是说ViewerContainer初始化结束才是Flex Viewer初始化的开始。 Flex Viewer初始化的脉络已经相当清晰,ConfigManager、UIManager、WidgetManager、MapManager在各自的初始化过程中对相应的事件进行监听,一旦ViewerContainer初始化完成,派发出CONTAINER_INITIALIZED事件,其它的准备工作将顺其自然,水到渠成。 我们注意到,初始化过程所涉及的各个模块都是相互透明的,彼此并不知道有对方的存在,而这些模块之所以能够亲密协作,关键就在于它们都只关心事件,事件机制使得这些模块之间实现松耦合。实际上,事件充斥着Flex Viewer的各个角落,随着对Flex Viewer理解的逐渐深入,对这一点的体会将更加明显。 3.4? Widget设计及实现? ? ? 图 3.3 Widget编程模型 Widget分为两种,Control Widget和Business Widget。Control Widget是指控制组件,比如NavigationWidget、HeaderControllerWidget、OverviewMapWidget等,这些Widget提供系统级别的功能,不针对具体业务功能;Business Widget是指业务组件,比如SearchWidget、BookmarWidget、GeoRSSWidget等,这些Widget提供具体业务功能。两种Widget都继承自BaseWidget,都由WidgetManager来管理,不同的是,在WidgetManager中有一个WidgetContainer来专门管理Business Widget。 两种Widget有共同的父类BaseWidget,BaseWidget实现了接口IBaseWidget,两者也就有了共同的接口。WidgetManager通过IBaseWidget来管理Widget,与具体的Widget解耦。Flex Viewer此处使用面向接口编程和依赖注入,实现了主体系统与Widget的松耦合。 u? IBaseWidget 该接口定义了WidgetManager与Widget进行交互的方法,BaseWidget实现了这个接口。 u? BaseWidget 该类是所有Widget的基类。只要某一组件继承自BaseWidget,WidgetManager即可对其进行管理。由于BaseWidget继承自Module,每一个Widget都将编译成独立的swf文件。 但两种Widget在具体实现上有所不同。Flex Viewer为Business Widget提供了统一的UI基类和接口,也就是WidgetTemplate和IWidgetTemplate。通常情况下,Control Widget都会使用自定义UI,但是这不是必须的。 u? IWidgetTemplate 该接口定义了BaseWidget与WidgetTemplate交互的方法。WidgetTemplate实现了这一接口。 u? WidgetTemplate 该类是IWidgetTemplate的一种默认实现,在具体的Widget实现中,同样可以使用自定义的WidgetTemplate,只要实现IWidgetTemplate接口即可。WidgetTemplate为Widget提供基本UI控件,包括窗口面板、带有图片按钮的标题栏等。使用Flex Viewer实现的WidgetTemplate,开发人员可以将更多的精力和时间放在实现业务逻辑上。 需要说明的是,Widget的设计在Flex Viewer 1.x版本和2.x版本中有所区别。在1.x中不存在Control Widget,比如菜单组件,菜单项是可配置的,但是菜单组件本身是不可配置的。2.x版本以后,Widget的概念扩大了,Flex Viewer中,凡是能看到的组件都是Widget,这样一来,控制组件可以像业务组件一样可配置,比如HeaderControllerWidget,灵活性大大提高。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |