网站地图
高级搜索
首页
技术论坛
博客
派计划
产品中心
资源中心
银弹在线
商城
goCom - SOA中国第一社区
SOA和WebService
|
面向构件
|
业务流程
|
EOS
|
综合技术
|
goCom吧
|
版务区
|
商务专区
SOA和WebService
|
面向构件
|
业务流程
|
EOS
|
综合
专家组计划
|
论坛版主计划
|
技术日讲师计划
Primeton EOS
|
Primeton BPS
OSOA专区
|
专题
|
技术日
|
活动
|
下载
推荐阅读
|
封面报道
|
特别报道
|
CIO锦囊
|
专栏
|
公司
|
银弹讨论
最新上架
|
银弹推荐
|
普通书籍
|
音像
|
护肤
|
生活
|
数码
goCom - 面向构件与SOA社区 讨论区
-
综合技术论坛
Share
Eclipse
RIA
数据库
Java
Wicket
企业应用
应用服务器
操作系统
平台厂商
主题选项
点击展开
HOVER展开
--------
打印主题
[无发表权] 请登录或者注册
版主:
jiaoly
lijj
个人资料
PureMVC软件架构分析与鉴赏
#1楼
总分
23 分
财富
25
威望
4
排名
:(
段位
概述
随着客户端程序的风起云涌,Adobe公司收购了Macromedia公司,针对Flesh的客户端进行研发,推出了Flex语言。Flex语言是类似与java的面向对象语言,编码格式又吸收了Delphi的编码风格,尽管Flex可以展现Flesh的炫目的客户端效果,全新的用户体验,但针对企业化的应用,仅有Flex是远远不够的,需要有合理的软件架构规范,于是Flex世界的MVC框架就应运而生了,PureMVC是Flex世界中的MVC模式的具体实现,相对于adobe官方的Cairngorm的Flex MVC框架,PureMVC更加简单实用。
PureMVC的整体架构
从使用者角度上讲,PureMVC设计的非常合理,对外的接口是Façade,由Façade来组织整个应用,其命名规范也显而易见,可以望文生义。其中Controller,Model,View是管理ICommand,IProxy,IMediator的容器,而ICommand,IProxy,IMediato是应用系统要扩展的MVC各层的接口。
这样,使用者就可以方便地扩展Façade,Command,Proxy,Mediator,来完成MVC各层的功能,没有特殊的需要,一般无需关注Model,View,Controller核心代码。
PureMVC的分层设计理念
PureMVC的各个层次各负其责,Façade实现统一管理,定义了系统的统一接口,使用者无需了解底层代码的运作方式。 Model层是实现与后台交互的层次,由Model类来管理Proxy,当然在Flex中也支持直接访问数据库,但大多数业务系统中,都是Flex作为客户端程序,而后台由Java或者.net来完成真正的业务操作。View层是显示层,在PureMVC中由Mediator实现对Viewcomponent的操作,如界面的简单校验等功能。Controller层是控制层,主要来处理一些数据转换等工作。下面具体介绍各层的具体功能及设计
Façade,外部应用的接口界面
从下图可以看出,Façade是对外的接口,同时管理Model,View, Controller,同时Façade是singleton。
1)在Java中实现singleton模式,构造方法都使用private方法,而这儿使用了public,但看第一句代码,呵呵!效果是一样的。但最好不要直接调用这个public方法
public function Facade( ) {
if (instance != null) throw Error(SINGLETON_MSG);
instance = this;
initializeFacade();
}
2)模板模式的应用
protected function initializeFacade( ):void {
initializeModel();
initializeController();
initializeView();
}
在Façade的构造方法中使用了模板模式,虽然Façade本身也实现了这些初始化方法,但都是获得Model,Controller,View,在具体应用中就可以initializeController()这三个方法,来注册相关的Proxy,Command,Mediator等。注意,实际上override initializeController()方法是比较常见的,而不常override initializeModel()和initializeView(), 最常见的是在Command的execute()中创建并注册Proxy,或者创建并注册Mediator。
3)如下的IFacade接口中,其中的Proxy,Command,Mediator管理方法都是借助于Model,Controller,View的管理方法来实现的。
4)Façade是实现INotifier接口的,所以Façade可以向系统发出消息或者通知,因为Flex是客户端的程序语言,其调用方式也是类似与Windows方式的观察者(observer)模式,Façade是统一的接口界面,所以几乎所有的外部调用都是通过sendNotification()方法。这个方法的调用的是notifyObservers()方法,而这个方法是如下的:
public function notifyObservers ( notification:INotification ):void {
if ( view != null ) view.notifyObservers( notification );
}
通常你只需要调用sendNotification()。
下面具体介绍PureMVC的MVC各层的架构设计:
Model与 Proxy
1)如上所述,Model也是Singleton设计模式,也无需使用new的方式创建,另外在企业应用中也很少直接扩展这个类,如果需要扩展,可以扩展initializeModel(),就相当于对Model的扩展了。
public function Model( )
{
if (instance != null) throw Error(SINGLETON_MSG);
instance = this;
proxyMap = new Array();
initializeModel();
}
2)Model是管理Proxy的容器类,使用类似与Java中的HashMap的数据类Array,来管理Proxy,代码类似:
protected var proxyMap : Array;
proxyMap[ proxy.getProxyName() ] = proxy;
包括后面谈到的Controller及View,都是这样管理其对象的,如获取某个值对象,
return proxyMap[ proxyName ];//简单吧,呵呵!
3)在registerProxy()和removeProxy()方法中,分别调用了Proxy的onRegister(),onRemove()方法,看到这儿,你是不是感到很熟悉。onXxxx()的命名规则,表示由子类实现详细内容来override父类的内容。抽象的原则是:共性化的东西向上(父类)抽象,个性化的东西向下(子类)延伸。即在实际应用中Proxy的onRegister(),onRemove()这两个方法是用来扩展我们自己的功能代码的。
Model:
public function registerProxy( proxy:IProxy ) : void
{
proxyMap[ proxy.getProxyName() ] = proxy;
proxy.onRegister();
}
Proxy:
public function onRegister( ):void {}
4)Proxy是我们要扩展的类,可以看出Proxy类实现了数据的交互,setData()和getData()方法实现数据的装载和获取,onRegister( )和onRemove( )可以实现相关Proxy注册和注销时的功能。
5)proxyName,是唯一表示系统中这个Proxy的名称,如上所述,Model管理Proxy是依赖类似与Java中HashMap的Array,所以必须是key->value(名值对),类似这样的设计还包括Mediator,Command,Façade等。
6)Proxy还实现了INotifier接口,所以也可以向外发送通知(消息),后面会具体讲解观察者模式在Flex中的广泛应用。
7)Proxy继承了Notifier类,在Notifier类中有Protected属性façade,这个Façade是系统中单例,所以可以通过这个Façade来注册相关的Mediator。
View与 Mediator
1)类似于Model ,View是管理Mediator的容器类,但View除了管理Mediator以外,还管理Observer,后面会专门讲Observer,其他如Mediator,Command,Proxy,Façade对Observer的注册都最终到View中来管理。
2)View作为管理Mediator和Observer的容器,利用的就是Flex的Array对象,Array对象如上面所说的Java的HashMap,也类似与Java中的Stack,其有push(), pop()等方法,
public function registerObserver ( notificationName:String, observer:IObserver ) : void
{
var observers:Array = observerMap[ notificationName ];
if( observers ) {
observers.push( observer );
} else {
observerMap[ notificationName ] = [ observer ];
}
}
这儿使用了push()方法,可以看出和Java 的HashMap的差异,HashMap是key/value,而Flex Array中一个key,可以对应多个Value,事实上是一个通知(消息),对应多个观察者(1..n)。
3)Mediator作为应用中要扩展的对象,被View容器管理,根据Flex的Array特性,每个Mediator必须有唯一的名称mediatorName,作为key,保存在Array中,同样Mediator也是继承了Notifier类,这样拥有Façade protected属性,可以注册相关Command,Proxy;同时又实现了INotifier接口,可以向外发送通知(消息)。
4)Mediator作为容器来管理ViewComponent,这样就可以把方便地控制界面展现。
Controller与 Command
1)
类似于Model和View,Controller也是Command的容器,通过Flex的Array来管理Command,同时Controller也是单例模式。
2)
在Command管理中,涉及到Observer监听的问题。
public function registerCommand( notificationName : String, commandClassRef : Class ) : void
{
if ( commandMap[ notificationName ] == null ) {
view.registerObserver( notificationName, new Observer( executeCommand, this ) );
}
commandMap[ notificationName ] = commandClassRef;
}
从这儿可以看出,凡是需要提供Observer监听功能的,都需要通过View来注册。
3)
的执行方法,即当Command被通知时,是调用Command的execute方法
Command
public function executeCommand( note : INotification ) : void
{
var commandClassRef : Class = commandMap[ note.getName() ];
if ( commandClassRef == null ) return;
var commandInstance : ICommand = new commandClassRef();
commandInstance.execute( note );
}
4)
与SimpleComman都实现了ICommand接口,其中MacroCommand实现了对ICommand的递归调用,这儿采用了类似于树的设计。
MacroCommand
public final function execute( notification:INotification ) : void
{
while ( subCommands.length > 0) {
var commandClassRef : Class = subCommands.shift();
var commandInstance : ICommand = new commandClassRef();
commandInstance.execute( notification );
}
}
其中subCommands就是一个Command数组。
5)
可以在protected function initializeMacroCommand():void中做如下扩展
override protected function initializeMacroCommand( ) : void
{
addSubCommand( com.me.myapp.controller.FirstCommand );
addSubCommand( com.me.myapp.controller.SecondCommand );
addSubCommand( com.me.myapp.controller.ThirdCommand );
}
这样,当Command初始化时就会来调用这个方法,因为你加入到Command数组中可能是SimpleCommand,那在执行时就直接执行它的execute方法,如果你加入的是MacroCommand对象,则执行MacroCommand的execute的递归方法。
观察者模式的应用
1)在PureMVC中大量使用了Notifier来完成发通知(消息)的机制,类似与java的调用,但和java的直接调用不同,是依赖观察者模式来实现的。
2)在Observer类中实现了设置上下文(调用哪个类?)和设置处理通知(消息)方法,这样一旦有消息发出,则捕获该消息,调用相应的类的某个方法来响应这个消息。
public function Observer( notifyMethod:Function, notifyContext:Object )
{
setNotifyMethod( notifyMethod );
setNotifyContext( notifyContext );
}
这个构造方法来初始化哪个类的那个方法来响应消息,就相当于把某个类封装到Observer内部。
3)如何来应用呢?我们来看Controller类中关于注册Command的一段代码
view.registerObserver( notificationName, new Observer( executeCommand, this ) );
View作为系统内部的唯一实例,来注册Observer,第一个参数是要响应的通知名称(如“Login”),第二个参数是创建一个Observer对象,该对象封装了响应的类是this(Controller)的方法“executeCommand”,而executeCommand方法从参数INotification中获取通知的名称,再根据名称从Controller中找到相应的Command来执行它的execute方法。
调用例子简介
上面讲了Observer的基本原理,为了更清晰地表现观察者模式的调用,如下图所示,调用的流程如下:
1)
创建ActionFacade的实例_facade,ActionFacade是Façade的实现类,并注册相关的Command,如在观察者模式讲到的,把相关的Command封装到Observer中,并注册到View内,其响应的通知名称为“login”
override protected function initializeController( ) : void
{
super.initializeController();
registerCommand( STARTUP, StratCommand );
this.registerCommand( LOGIN, LoginCommand );
}
2)
调用_facade.login(user)
public function login( user:UserVo ):void
{
sendNotification( LOGIN, user );
}
3)
实际上是调用父类Façade的sendNotification方法
public function sendNotification( notificationName:String, body:Object=null, type:String=null ):void
{
notifyObservers( new Notification( notificationName, body, type ) );
}
而Façade方法notifyObservers
public function notifyObservers ( notification:INotification ):void {
if ( view != null ) view.notifyObservers( notification );
}
也就是说要调用View的notifyObservers方法
4)
的notifyObservers方法如下,遍历所有关注这个通知(名称)的Observer,依次执行这些Observer的notifyObserver方法。
View
public function notifyObservers( notification:INotification ) : void
{
if( observerMap[ notification.getName() ] != null ) {
var observers:Array = observerMap[ notification.getName() ] as Array;
for (var i:Number = 0; i < observers.length; i++) {
var observer:IObserver = observers[ i ] as IObserver;
observer.notifyObserver( notification );
}
}
}
5)
下面来看Observer的notifyObserver方法
public function notifyObserver( notification:INotification ):void
{
this.getNotifyMethod().apply(this.getNotifyContext(),[notification]);
}
这个方法很简单,获取这个Observer封装的响应通知的方法(如exectue()),并把对应的上下文(如Controller),和通知作为参数来执行,呵呵!很像java中的反射机制。
6)
如在观察者模式的应用中讲到的,执行了Controller的executeCommand方法,从而遍历Command数组,找到响应这个通知的Command(如LoginCommand),并执行这个Command的exectue方法。
总结
PureMVC相对来说,比较简单,对于初学者来说比较容易理解和应用,也可以作为学习设计模式的简易教材。同时作为Flex的框架性代码,从另外的角度可以学习Flex编程思想及设计思路。
努力,在于我热爱我的事业,与中国的软件一起走向成熟,走向世界。
联系作者:
lijj_72@hotmail.com
2008/8/6 14:15
锐捷工作流 - BPS Express产品发布,
免费下载
参与RIA产品调研 赢取goCom纪念T恤
动量ODE
普元SOA业务流程平台BPS 6.1即将发布
普元融资成功新闻发布会
Primeton EOS 产品下载
Primeton BPS 产品下载
[无发表权] 请登录或者注册
发表回复
账号
用户名
密码
登录
内容:
字体大小
xx-small
x-small
small
medium
large
x-large
xx-large
字体
Arial
Courier
Georgia
Helvetica
Impact
Verdana
字体颜色
#000000
#000033
#000066
#000099
#0000CC
#0000FF
#003300
#003333
#003366
#003399
#0033CC
#0033FF
#006600
#006633
#006666
#006699
#0066CC
#0066FF
#009900
#009933
#009966
#009999
#0099CC
#0099FF
#00CC00
#00CC33
#00CC66
#00CC99
#00CCCC
#00CCFF
#00FF00
#00FF33
#00FF66
#00FF99
#00FFCC
#00FFFF
#330000
#330033
#330066
#330099
#3300CC
#3300FF
#333300
#333333
#333366
#333399
#3333CC
#3333FF
#336600
#336633
#336666
#336699
#3366CC
#3366FF
#339900
#339933
#339966
#339999
#3399CC
#3399FF
#33CC00
#33CC33
#33CC66
#33CC99
#33CCCC
#33CCFF
#33FF00
#33FF33
#33FF66
#33FF99
#33FFCC
#33FFFF
#660000
#660033
#660066
#660099
#6600CC
#6600FF
#663300
#663333
#663366
#663399
#6633CC
#6633FF
#666600
#666633
#666666
#666699
#6666CC
#6666FF
#669900
#669933
#669966
#669999
#6699CC
#6699FF
#66CC00
#66CC33
#66CC66
#66CC99
#66CCCC
#66CCFF
#66FF00
#66FF33
#66FF66
#66FF99
#66FFCC
#66FFFF
#990000
#990033
#990066
#990099
#9900CC
#9900FF
#993300
#993333
#993366
#993399
#9933CC
#9933FF
#996600
#996633
#996666
#996699
#9966CC
#9966FF
#999900
#999933
#999966
#999999
#9999CC
#9999FF
#99CC00
#99CC33
#99CC66
#99CC99
#99CCCC
#99CCFF
#99FF00
#99FF33
#99FF66
#99FF99
#99FFCC
#99FFFF
#CC0000
#CC0033
#CC0066
#CC0099
#CC00CC
#CC00FF
#CC3300
#CC3333
#CC3366
#CC3399
#CC33CC
#CC33FF
#CC6600
#CC6633
#CC6666
#CC6699
#CC66CC
#CC66FF
#CC9900
#CC9933
#CC9966
#CC9999
#CC99CC
#CC99FF
#CCCC00
#CCCC33
#CCCC66
#CCCC99
#CCCCCC
#CCCCFF
#CCFF00
#CCFF33
#CCFF66
#CCFF99
#CCFFCC
#CCFFFF
#FF0000
#FF0033
#FF0066
#FF0099
#FF00CC
#FF00FF
#FF3300
#FF3333
#FF3366
#FF3399
#FF33CC
#FF33FF
#FF6600
#FF6633
#FF6666
#FF6699
#FF66CC
#FF66FF
#FF9900
#FF9933
#FF9966
#FF9999
#FF99CC
#FF99FF
#FFCC00
#FFCC33
#FFCC66
#FFCC99
#FFCCCC
#FFCCFF
#FFFF00
#FFFF33
#FFFF66
#FFFF99
#FFFFCC
#FFFFFF
范例 Example
[
更多...
]
版权归Primeton普元公司所有 沪ICP备05008205号
关于goCom
|
联系我们
|
联系普元
|
隐私权声明
|
XOOPS