posts - 176, comments - 240, trackbacks - 0, articles - 7

[导入]jsplet:对Model 2模式的批判

Posted on 2005-11-15 12:31 canonical 阅读(340) 评论(1)  编辑  收藏 所属分类: Witrix开发平台

   在Jsp Model 2模型中, 用户的所有请求提交给Controller Servlet, 由Controller进行统一分配, 并且采用推的方式将不同的UI显示给用户。 这种推方式在很多人看来是一种优点,因为在Struts等MVC实现中具体推送的UI可以在配置文件中配置,配置完成后还可以通过一些可视化分析工具得到 整个站点地图。在Model2模式中基本的访问格式为:
       action.do?其他参数  

我 本人从未应用过Model2模式,但与我们的jsplet框架对比,我认为这种推送方式在大多数情况下并不是什么优点。如果将一次web访问看作是一次函 数调用,则按照Model2模式,这个函数的返回情况是不确定的,需要由一个额外的配置文件来确定。而我们知道,一个返回情况不确定的函数一般不是什么良 好的设计。在我们的框架设计中,一个基本的观点是尽量将自由度暴露给实际控制它的人。实际上,在大多数情况下,页面编制人员知道应该使用哪个页面来显示数 据,他们并不需要一个额外的配置文件。Jsplet使用如下的url格式:
       视图jsp?objectName=模型对象名&objectEvent=响应事件名&其他参数
举一个具体的例子:
  
http://my.com/demo_view.jsp?objectName=/@Demo&objectEvent=test

demo_view.jsp是指定的显示页面, 其代码如下:
[code]
<%@ include file = "/engine.jsp" %>
<!-- 相当于在jsp模型中增加了一个新的变量thisObj,从而实现jsp页面的对象化 -->
<c:out>${thisObj.testVar}</c:out>
[/code]
objectName被WebEngine映射到session中的一个对象,在demo_view.jsp中成为thisObj这个变量,这就相当于java语言中的this指针,从而实现了jsp页面的对象化。

WebEngine还将objectEvent映射到一个Action响应函数并自动调用它,具体的Action代码写在一个独立的java文件或者jsp文件中。
DemoAction.jsp
[code]
<%@ include file = "/jsp_action_begin.jsp" %>
<%!
    //
 // objectName映射为thisObj, objectEvent=test映射对actTest的调用
 // 在这里增加一个actXXX函数之后,即可通过objectEvent=XXX来访问,不需要任何配置
    public Object actTest(){
  // thisObj中的变量可以在视图中使用
  thisObj.set("testVar","hello");
  return success();
 }

 // 如果存在actBeforeAction函数,则该函数在所有action函数之前调用
 public Object actBeforeAction(){
  return success();
 }

 // 如果存在actAfterAction函数,则该函数在所有action函数之后调用
 public Object actAfterAction(){
  return success();
 }
%>
<%@ include file="/jsp_action_end.jsp" %>
[/code]

在Jsplet框架中只需要注册对象,而不需要单独注册每个action。
register.jsp
[code]
<%
    WebEngine.registerType("Demo", new WebActionType("/demo/action/DemoAction.jsp"),pageContext);
%>
[/code]

与Jsplet 框架对比,Model2是对action的建模而不是对object的建模,即它相当于将objectName,objectEvent和 view.jsp绑定在一起定义为一个访问点action.do,绑定过程中需要一个配置文件来固化view.jsp和action之间的联系。因此, Model2并没有完全分离view和model,它隐含假定着objectName只具有一个objectEvent, 并且绑定了一个具体的view(出错页面除外)。
例如, 我们需要两个不同的view来显示同一个数据,则在Model2程序中可能需要配置两个独立的访问点,而在我们的框架中只需要使用两个不同的url:
a_view.jsp?objectName=/@Demo&objectEvent=test
b_view.jsp?objectName=/@Demo&objectEvent=test
同样的web程序甚至可以在前台通过XMLHTTP方式来调用而不需要额外配置!

在Jsplet框架中采用的是对象化的方式而不是Action化的方式,因此存在着多种面向对象的扩展,而所有的扩展都直接体现在url格式的细化上,一切都在阳光下。
  在Jsplet中objectName是WebObject的名称,在全系统内唯一,其格式定义为:
objectScope@objectType$objectInstanceId
1. 对象类型objectType
  我们需要注册的是对象类型而不是完整的对象名,一个对象类型可以对应于无数个完整的对象名,例如我们注册了Demo类型的WebObject, 则
objectName=/@DemoobjectName=/left/@Demo对应的处理文件都是DemoAction.jsp。
2. 对象生命周期控制objectScope
  objectScope为WebObject所在的域,其格式符合Unix路径命名规范。JSP模型本身支持一些预定义的对象域,包括page, request, session, application等。但为了能够反映现实世界中的对象组织结构,对象域必须是允许自定义的。objectScope被组织成一个树形结构,这是一个 基本的控制结构,其控制策略为
     同时存在的对象域之间必须存在线性序关系(order)
  当系统访问某一对象时,如果该对象所在的对象域不能和现有对象的域处在同一"路径"下(即当对象域之间不能建立父子关系时),系统就会自动销毁不兼容路径 分支下的所有对象。 这种精细的控制策略保证了系统的可扩展性,因为模型上可以保证始终只有一部分对象被创建。
对象转移                                                           系统动作 
/main/@MyObject ==> /main/left/@OtherObject                       无
/main/left/@OtherObject ==> /main/@MyObject                       无
/main/left/@OtherObject ==> /main/left/@MyObject                  无
/main/left/@OtherObject ==> /main/right/@MyObject                自动销毁/main/left子域下的对象,如/main/left/@OtherObject
 
3. 对象实例标识 objectInstanceId
 如果在某一对象域中需要包含多个同一类型的对象,可以通过objectInstanceId来加以区分,这样在同一个页面上我们可以使用多个同样类型的对象。

Jsplet中另外一个扩展是通过事件路由来支持jsp子页面的对象化。例如
http://my.com/demo_main.jsp?objectName=/@Main&eventTarget=/@Sub&objectEvent=test
如果指定了eventTarget参数,则objectEvent由eventTarget对应的对象来响应。
在jsp文件内部我们可以通过include语法来引入子对象,例如
   <jsp:include page="
sub_view.jsp?objectName=/@Sub" />
(注:我不是非常清楚Tapestry具体是如何实现对象化的,熟悉Tapestry的朋友可以介绍一下)

在Jsplet中可以通过配置文件来支持对Action的interception, 例如
[code]
<factory>
<listener-filter  class="global.LogFilter" />
<post-listener class="global.CommonActions"/>

<type name="Demo">
 <!-- 如果未指定object, 则缺省为WebObject类型 -->
 <object class="demo.MyWebObject" />
 <listener>
  <filter event="query*|select*" class="demo.LogFilter" />
  <url-listener url="/demo/DemoAction.jsp" />
  <url-listener url="/demo/DemoAction2.jsp" />
 </listener>
</type>

</factory>
[/code]
在上面这个配置文件中,DemoAction.jsp和DemoAction2.jsp是chain关系,即事件响应的传播模型中,如果event没有被标记为stopPropagation,就会传递到下一个listener。

综上所述,可以看到在目前多变的需求环境下,Model 2已不是一种非常完善的Web程序模式,一些重要的设计需求在Model 2模式的推方式中很难得到合适的表达。

Feedback

# re: [导入]jsplet:对Model 2模式的批判  回复  更多评论   

2006-01-17 16:14 by freeboy
Model2所有的路由(就是路径转向),由配置文件指定.用户必须有一个Action顶点才能到达其他的点.所有的过程都是经过了配置文件.是典型的接收请求---->处理请求--->显示.---------------太集中的处理请求模式

而你这个jsplet是通过jsp页面的转向.然后拦截(engine.jsp).完成数据填充(也就是Action功能),因为你在URL指定了jsp路径.不需要继续转向了.所以也没有了配置文件.
Action中的转向配置分散到了各个URL中.然后你通过register.jsp集中对这些Action进行管理.用户要什么显示------>系统处理(通过Action权限验证,填充this数据)------>返回.------------------分散处理界面模式,适度集中,减少难度.

觉得两种结构各有优劣,偏向于页面转向的这种模式比较好.可以先写好所有的页面转向关系(界面流程),然后在也写Action也不迟,适合快速原型模型.而向struts,必须写好Action,配置转向,绘制简单页面.在页面上写上基本流程.Action模式更适合权限控制,尤其是复杂的权限控制.

你这个问题难以解决的问题:这个函数的返回情况是不确定的,需要由一个额外的配置文件来确定.如果确实需要这种情况呢,根据传入的参数不同,得到不同结果.
如:用户通过一个下拉列表选择输出直方图,表格,曲线,然后点击一个按钮让产生输出.
觉得配合两种更好一点,不过好像没有这种东西:(,而且复杂度会增加.


只有注册用户登录后才能发表评论。


网站导航: