﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-canonical-随笔分类-软件开发</title><link>http://www.blogjava.net/canonical/category/4851.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 13 Jan 2008 13:10:39 GMT</lastBuildDate><pubDate>Sun, 13 Jan 2008 13:10:39 GMT</pubDate><ttl>60</ttl><item><title>C++配置管理</title><link>http://www.blogjava.net/canonical/archive/2008/01/12/174892.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sat, 12 Jan 2008 12:58:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2008/01/12/174892.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/174892.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2008/01/12/174892.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/174892.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/174892.html</trackback:ping><description><![CDATA[&nbsp; 自从离开学校就基本上不再使用C++了，最近却又因为项目上的原因重新走入这一迷失的世界, 感觉很是缺乏一些顺手的工具。首先就是做配置管理有点麻烦, 因为缺乏反射机制, 无法直接映射, 所以一般需要手工书写配置设置功能. <br />
&nbsp; 我们希望配置类在配置阶段能够支持动态属性名，<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;GConfig&nbsp;cfg;<br />
&nbsp;&nbsp;cfg.set(</span><span style="color: #000000;">"</span><span style="color: #000000;">bgColor.b</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">3.0</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;cfg.set(</span><span style="color: #000000;">"</span><span style="color: #000000;">lightEnabled</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #0000ff;">false</span><span style="color: #000000;">);<br />
<br />
&nbsp;&nbsp;t_float&nbsp;b&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;cfg.get(</span><span style="color: #000000;">"</span><span style="color: #000000;">bgColor.b</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;bool&nbsp;l&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;cfg.get(</span><span style="color: #000000;">"</span><span style="color: #000000;">lightEnabled</span><span style="color: #000000;">"</span><span style="color: #000000;">);</span></div>
<br />
&nbsp;&nbsp;&nbsp; 但是内部使用时支持直接的属性访问，便于编译器检查， 也提高运算速度。<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t_float&nbsp;b&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;cfg.bgColor.b;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;l&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;cfg.lightEnabled;</span></div>
<br />
<br />
所幸C++的类型系统能够偷偷的去干很多见不得人的勾当，因此便有了下面这个简易机制。<br />
<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">#define&nbsp;S_P(x)&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">{</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(strcmp(name,#x)&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">) { x&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;value;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">; } }&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
#define&nbsp;G_P(x)&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">{</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(strcmp(name,#x)&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">) { value&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;x;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">; } }&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;_GConfig{<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br />
&nbsp;&nbsp;bool&nbsp;lightEnabled;<br />
<br />
&nbsp;&nbsp;t_float&nbsp;minX;<br />
&nbsp;&nbsp;t_float&nbsp;maxX;<br />
&nbsp;&nbsp;t_float&nbsp;minY;<br />
&nbsp;&nbsp;t_float&nbsp;maxY;<br />
<br />
&nbsp;&nbsp;_GConfig(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;initialize&nbsp;all&nbsp;primitive&nbsp;members</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;memset(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">,</span><span style="color: #000000;">0</span><span style="color: #000000;">,sizeof(_GConfig));<br />
&nbsp;&nbsp;}<br />
};<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;GConfig:&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;_GConfig{<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br />
&nbsp;&nbsp;GColor&nbsp;bgColor;<br />
<br />
&nbsp;&nbsp;GConfig(){<br />
&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;_variant_t&nbsp;get(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;name){<br />
&nbsp;&nbsp;&nbsp;&nbsp;_variant_t&nbsp;value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;get(name,value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;value;<br />
&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;get(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;name,_variant_t</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;value){<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(lightEnabled);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(minX);<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(maxX);<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(minY);<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(maxY);<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(bgColor.r);<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(bgColor.g);<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(bgColor.b);<br />
&nbsp;&nbsp;&nbsp;&nbsp;G_P(bgColor.a);<br />
&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;set(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;name,&nbsp;_variant_t&nbsp;value){<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(lightEnabled);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(minX);<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(maxX);<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(minY);<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(maxY);<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(bgColor.r);<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(bgColor.g);<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(bgColor.b);<br />
&nbsp;&nbsp;&nbsp;&nbsp;S_P(bgColor.a);<br />
&nbsp;&nbsp;}<br />
};<br />
</span></div>
<br />
_variant_t是VC++在&lt;comdef.h&gt;中提供的对变体数据类型的封装。使用S_P和G_P这样的宏可以由编译器检查变量名的正确性。<br />
<img src ="http://www.blogjava.net/canonical/aggbug/174892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2008-01-12 20:58 <a href="http://www.blogjava.net/canonical/archive/2008/01/12/174892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]OpenSource: 超越软件工程</title><link>http://www.blogjava.net/canonical/archive/2007/12/08/166189.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Fri, 07 Dec 2007 18:58:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2007/12/08/166189.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/166189.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2007/12/08/166189.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/166189.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/166189.html</trackback:ping><description><![CDATA[<font style="color: #000000;" size="3">&nbsp;&nbsp;&nbsp; 现在讲软件工程的, 所谈论的多半是项目工程,
即如何在有限的时间内配置使用有限的资源在单个项目中达到既定的目标. 传统上, 在这一领域基于预测和计划的瀑布方法曾经占据主流,
但是随着项目的日益复杂化, 各种基于演化(evolution)思想的工程方法在实证中逐渐发展起来. 在时空跨度更大的软件工程领域,
例如延展到软件的不同版本以及多个相似项目的工程中, 演化更是逐渐取得了无可置疑的主导地位. 但是, 从另一个方面说,
目前所有这些软件工程方法所推崇的演化实际上都是非常有限的, 它们通过迭代(iteration)所能够描述的演化过程都只是片断性的,
例如一个项目中的演化, 一个软件产品的演化, 最大的莫过于一整条软件产品线的演化. 所有这些演化过程都面临着一个天然的屏障:
商业公司.在公司内部, 知识或代码可以由开发人员携带到下一个项目, 或者从一个小组传播到另外一个小组, 在新的基础上继续演化的进程.
但是核心的知识或者代码一般只能通过商业交易传达到其他公司, 这是一条非常受限制的途径. 而一个单个公司所开发的软件包, 即使是平台级的产品,
如果只是内部使用, 受限于该公司所从事的业务领域, 其所面临的使用检验也是非常有限的. 而且出于经济上的原因,
单个公司往往无力支撑多个实现同样功能的解决方案, 因而它倾向于消灭软件中的多样性, 这有可能会进一步限制演化的进程. &nbsp;<br />
&nbsp;&nbsp;&nbsp;
开源(OpenSource)软件为软件演化创造了新的可能性.商业友好的开源软件可以被不同的公司自由的运用于不同的业务,
因而可以参与到不同的局部演化过程中. 在应用的过程中, 开源软件面临着巨大的重构压力(这往往是超越了应用最广泛的封闭源码软件包的),
有可能保持更快的演化速度. 而通过对开源软件的回馈, 对开源软件的改进可以传播到时空范围跨度巨大的软件开发过程中. 而且基于源码的开放性,
开发人员的知识交流也随之开放起来. 类比于Darwin进化论, 我们可以说开源驱动了整个软件业界的共同进化(co-evolution).<br />
&nbsp;&nbsp;&nbsp; 多年前, Eric Raymond在著名的文章"大教堂和市集"中 <a href="http://263.aka.org.cn/Docs/c&amp;b.html">http://263.aka.org.cn/Docs/c&amp;b.html</a>,
提出了开源的工程价值, 但其所关注的重点仍然只是单个软件如何在开源的模式下演化, 从今天的观点看来, 这篇战斗檄文已经显得有些局促了.
开源所造就的巨大演化空间远远超越了软件工程所能够提供的. 开源软件现在已经在商业开发领域站稳了脚跟,也渐渐超越了单个公司能够控制的范围.
可以说开源软件的发展是无可逆转的, 我们已经不会也不应该再回复到原先的封闭世界中. </font>
<img src ="http://www.blogjava.net/canonical/aggbug/166189.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2007-12-08 02:58 <a href="http://www.blogjava.net/canonical/archive/2007/12/08/166189.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于JSF</title><link>http://www.blogjava.net/canonical/archive/2007/07/29/133193.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 29 Jul 2007 15:43:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2007/07/29/133193.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/133193.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2007/07/29/133193.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/133193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/133193.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; JSF(Java Server Faces)技术从发布时间上看已经是一种比较古旧的技术了，但是目前仍未能成为主流的开发实践。从我知道这种技术开始, 我对它的判断就与我最早对于EJB的判断一样, 它们都在某种程度上捕获了真正的需求,但是因为它们自身诡异的技术路线.我很怀疑是否这些标准制定者故布疑阵, 便如Microsoft的OLE技术一样, 故意抛出一个错误的方向, 将大批组件开发商带入死局. <br>&nbsp;&nbsp; JSF技术是一种双重的存在：它首先是一种标准，然后也提供了一种缺省的实现。但是从这两方面，我都无法看到JSF的未来。<br>&nbsp;&nbsp; 从设计上说，强类型的视图模型对象层与Witrix的架构设计原则严重冲突。Witrix的基本架构是浏览器和后台服务器通过具有显明语义的url实现两分，这也是所谓REST风格的一种内在要求。隐蔽了链接的技术破坏了基本的web超链模型. 为了获得那么一点点结构控制能力, 做出这样的抽象是不合适的.JSF的配置模型继承了structs的传统，仍然是那样的冗长繁杂。我们是否真的需要这些配置文件，还是希望像ROR那样在代码中直接完成一切？<br>&nbsp;&nbsp; 不能在标准的浏览器中预览. 可以说创造了一个JSF IDE的市场, 但是这无疑是一个无聊的市场. 现在有一些备选的方案, 如Facelets, 使得jsf可以采用属性语法, 但是只要想想仅仅为了这么一点小小的修正所需要付出的开发量就足以让人崩溃。<br>&nbsp;&nbsp; JSF提供了组件级别的事件响应机制，因此似乎是AJAX应用的理想场所．但从Witrix平台的开发实践来看，JSF对于AJAX的使用是受限制的，有着很大局限性的．组件事件响应并不一定要采取JSF那种体系结构．<br>&nbsp;&nbsp; 从实现角度上说，基于jsp tag可以说是JSF的致命弱点之一. jsp tag从设计之始就一直是未经过实践考量，其设计无法支撑复杂的控件架构. 特别是早期JSF与标准的JSP tag不能互通实际上是明显的设计缺陷, 而且性能问题是内置在该设计中的. 现在虽经多个版本的不断补救, 但是为了兼容性, JSP Tag负担过重, 它始终是基于文本处理模型，实际上不可能有什么本质性的进步.　JSP tag模型过分孱弱必然造成JSF设计中大量处理过程堆叠到界面对象层，更加剧了JSF的模型复杂度和性能瓶颈。 实际上根据Witrix平台中tpl模板技术的设计经验，大量界面构建过程是可以在模板层以直观的方式完成的，而不需要借助视图模型对象。<br>&nbsp;&nbsp; 所有问题的一个集中体现就是增加一个新的JSF组件绝对不是一件平凡的事情．如果有一天这个问题可以得到解决，那时的JSF从思想和实现上都必然和现在的JSF有着本质性的区别．<br><img src ="http://www.blogjava.net/canonical/aggbug/133193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2007-07-29 23:43 <a href="http://www.blogjava.net/canonical/archive/2007/07/29/133193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate动态化</title><link>http://www.blogjava.net/canonical/archive/2006/07/23/59703.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 23 Jul 2006 13:13:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/07/23/59703.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/59703.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/07/23/59703.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/59703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/59703.html</trackback:ping><description><![CDATA[  hibernate的应用中一般总是将entity映射为强类型的java类，这为程序操纵带来很多便利，同时可以将大量动态过程隐蔽在对象包络之下。映射为java类的一个主要问题在于无法在程序运行时刻对于程序进行修改，而数据结构的局部修改几乎是无法避免的。hibernate3本身支持动态数据模型，它允许我们把entity映射为Map数据类型, 当数据结构发生变化的时候, 只需要修改hbm文件即可改变映射模型,而不需要修改java实体类代码. <br />    在hbm定义文件中,如果我们不指定name属性,而是指定entity-name属性,则我们可以将entity映射为Map, 而不是一个java实体类.<br />  &lt;class <br />    entity-name="test.DynamicEntity" <br />    table="DYNAMIC_ENTITY"<br />  &gt;...&lt;/class&gt;<br />  此外, 也可以选择将部分字段动态映射到Map<br />  &lt;class ...&gt;<br />    &lt;dynamic-component name="dynamicAttributes"&gt;<br />      &lt;property name="foo" column="FOO"/&gt;<br />      &lt;property name="bar" column="BAR"/&gt;<br />    &lt;/dynamic-component&gt;<br />  &lt;/class&gt;<br />在HQL语句中可以直接使用o.dynamicAttributes.foo来访问foo属性，所有操作与普通属性相同。<br />  为了实现hiberante映射模型的动态更新，我们首先需要实现sessionFactory的动态更新。目前hibernate的实现只允许从hbm文件重建sessionFactory, 即新建一个sessionFactory替换原有的sessionFactory, 在使用spring的情况下，这需要对org.springframework.orm.hibernate3.LocalSessionFactoryBean进行小小的hack。<br />  为了将动态属性和普通属性同样对待，要求在操作实体对象属性的时候需要能够自动处理nested property, 即需要如下类似的方法：entityDao.getProperty(entity,"dynamicAttributes.foo"), entityDao.setProperty(entity,"dynamicAttributes.foo", attrValue).<br />  为了使得应用程序自动处理新增属性，要求程序是meta驱动的：当实体对象增加了一个属性时，只需要修改meta文件，即可完成对于该属性的增删改查汇总等普通应用需求。<img src ="http://www.blogjava.net/canonical/aggbug/59703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-07-23 21:13 <a href="http://www.blogjava.net/canonical/archive/2006/07/23/59703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Ruby DSL</title><link>http://www.blogjava.net/canonical/archive/2006/07/16/58462.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 16 Jul 2006 14:41:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/07/16/58462.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/58462.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/07/16/58462.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/58462.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/58462.html</trackback:ping><description><![CDATA[  最近ruby语言的流行似乎再次引发了DSL(Domain Specific Language)讨论的热潮。从语法表现形式上看，通过对于ruby语言的深度hack, 充分挖掘ruby语言的某些语法特征，可以使得正常的ruby语句看起来比其他计算机语言更接近于人类的自然语言，某些人因此认定ruby语言是DSL的天然载体。但是在我看来，具体语言的语法表达形式对于DSL的核心价值而言并不是最关键的。<br />   首先，DSL的核心在于高效的表达语义，而并不在于是否接近自然语言。接近于自然语言并不意味着更加domain， 因为自然语言也是一种通用语言，它未必能够比采用其他语法形式的语言更加有效的对domain事物进行描述。典型的有数学符号和化学分子式。<br />   第二，作为DSL, 紧凑的表达形式是一方面，另一方面是这种表达形式的稳定性，即如何防止人们写出不符合DSL规范的语句。ruby语言的片断直接作为DSL无疑是一种naive的解决方案，我们可以轻易写出大量不同形式的ruby语句，而它们在语义上是等价的（这意味着通过单元测试也无法发现它们的不同），即人们不按照设计的DSL语法书写，这造成DSL的解体。<br />   作为一种DSL构造语言，其核心能力在于如何将second class的domain中的概念（非语言本身内置的概念）封装到first class的表达形式中。ruby作为一种动态语言，可以更加轻易对于自身meta data进行内省，典型的如ruby中的ActiveRecord设计. 但是在我看来，这种概念提升能力在ruby的语法结构中也是有限的，原因恰在于ruby的语法太多样化了。实际上，我更加看好xml结构的均一性。<img src ="http://www.blogjava.net/canonical/aggbug/58462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-07-16 22:41 <a href="http://www.blogjava.net/canonical/archive/2006/07/16/58462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>about GWT</title><link>http://www.blogjava.net/canonical/archive/2006/05/19/47114.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Fri, 19 May 2006 13:27:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/05/19/47114.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/47114.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/05/19/47114.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/47114.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/47114.html</trackback:ping><description><![CDATA[  <a href="http://code.google.com/webtoolkit/">http://code.google.com/webtoolkit/</a><br />  最近google发布了Google Web Toolkit(GWT)开发包，这是一种使用java语言开发AJAX应用的开发框架。从技术上看，GWT并没有什么新鲜之处，类似的概念在多年之前就已经有各种尝试了，这些尝试从未真正吸引到足够的注意。GWT的优势也许在于提供了一套模拟工具，另外可能在屏蔽browser的兼容性和bug方面做得更好一些，但是真正的技术思想并没有什么突破. Ruby On Rails同样是试图将ruby语言直接映射到前台程序, 但是它通过一个通用的prototype.js库最小化了ruby语言和js语言之间的区别,在概念上要比GWT的java2js的compiler概念要更加新颖一些. (<a href="http://mir.aculo.us/stuff/COR_20060413_RailsAjax.pdf">http://mir.aculo.us/stuff/COR_20060413_RailsAjax.pdf</a>)<br />  对于web开发而言，我总认为要发挥web的特色，而不是把它约束到其他领域的开发模式上。js+dom+html文本所能做到的结构控制程度要远远超越组件技术，我也从未发现学习java要比学习html要更加容易。也许对于某些对于web一无所知的java开发人员来说，GWT有些意义，也许GWT会特别适合于某些特定的领域，但是作为一种通用的开发框架，我并不看好它。<br /><img src ="http://www.blogjava.net/canonical/aggbug/47114.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-05-19 21:27 <a href="http://www.blogjava.net/canonical/archive/2006/05/19/47114.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AJAX and AJAH and MVC</title><link>http://www.blogjava.net/canonical/archive/2006/05/09/45295.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Tue, 09 May 2006 14:56:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/05/09/45295.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/45295.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/05/09/45295.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/45295.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/45295.html</trackback:ping><description><![CDATA[  传统的Mode2模式的服务器端框架在处理AJAX应用的时候存在一定的不适应性，这主要的原因在于Model2基于推模式，它隐含的假设是基于action的处理结果生成整个页面，而AJAX应用中所强调的是页面局部的变化，只更新发生变化的部分，而不是重新生成整个页面（change instead of create), 这两者之间存在着内在的不协调。有些人推崇后台服务程序只返回xml数据的方法，将显示层完全推到前台。虽然在前台通过js脚本操纵DOM节点可以实现非常细粒度上的控制，但是我们并不总是需要最细粒度上的控制权的。例如现在我们在前台实现一个grid控件， grid控件本身只需要控制到单元格层次即可，而不需要对于单元格里存放什么内容有预先的假设. grid.getCell(i,j).innerHTML = cellHtml是非常自然的一种解决方式。完全通过dom来构造界面面临着众多问题，除了浏览器bug这种挥之不去的噩梦之外，在实现过程中我们往往会引入对界面元素的大量限制条件，而无法做到集成各种来源的控件。<br />  在服务器端生成页面片断的方式也称为AJAH，表面上看起来它比AJAX要简易一些，是很多服务器端框架引入AJAX概念的乡间小径。但有趣的是在基于拉模式(pull mode)的服务器端MVC框架中，AJAH是在架构上比AJAX更加灵活的一种方式。在witrix平台的jsplet框架中，web访问的基本形式如下:<br />   /view.jsp?objectName=XXObject&amp;objectEvent=XXEvent&amp;otherArgs&amp;tplPart=XXPart<br />其中objectName对应于后台的服务对象，objectEvent参数映射到服务对象的方法，view.jsp是对于后台对象进行渲染的模板页面，而tplPart参数可以指定只使用模板的某一部分进行渲染。如果我们选择json.jsp或者burlap.jsp作为渲染模板，则可以退化到返回数据而不是内容的方式。在js中进行简单的封装后我们可以通过如下方式进行远程调用：<br />  new js.Ajax().setObjectName("XXObject").setObjectEvent("XXEvent").addForm("XXFormId").callRemote(callbackFunc);<br />   它对应的url请求为<br />   /json.jsp?objectName=XXObject&amp;objectEvent=XXEvent&amp;...<br />对于同样的后台业务处理，我们可以自由的选择渲染模板，则可以很自然的得到更多的处理方式，例如返回javascript代码来实现对于前台的回调。<br /><img src ="http://www.blogjava.net/canonical/aggbug/45295.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-05-09 22:56 <a href="http://www.blogjava.net/canonical/archive/2006/05/09/45295.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]锐道dorado</title><link>http://www.blogjava.net/canonical/archive/2006/04/02/38732.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 02 Apr 2006 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/04/02/38732.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/38732.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/04/02/38732.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/38732.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/38732.html</trackback:ping><description><![CDATA[
		<font style="color: rgb(0, 0, 0);" size="3">
				<a href="http://www.bstek.com/">http://www.bstek.com/</a>
				<br />   
上海锐道的Dorado框架号称是一个基于构件技术的、面向B/S和多层架构体系的web应用开发平台，
其前身称为Extra。从具体功能来看，如果将其看作是一个全功能的web应用开发平台，　那它现在的功能集显得就太单薄了一些,
其主要部分还是提供了一些前台的界面控件, 其他如web框架部分,很像是struts的一个简化版，没有什么特异之处。 <br />    Dorado的技术特点是大量采用ajax技术来实现前台控件. 其前后台交互采用了自定义的基于xml格式的rpc方式, 而数据绑定使用了xml数据岛,例如<br />    &lt;xml id="__datasetEmployee" &gt;<br />    &lt;records&gt;<br />    &lt;record isCurrent="true"  state="none" &gt;<br />    &lt;new&gt;,~73~73~73~73~73,~68~68,~44~31~32,true,true,295113600000,2034.0,,&lt;/new&gt;<br />    &lt;/record&gt;<br />    &lt;/xml&gt;<br />    record内部使用的是Dorado私有的编码/解码规则, 大概是为了压缩数据量吧.<br />   
从Dorado目前提供的界面来看还是比较丰富的,基本满足了一般信息系统开发的需求, 但是其可扩展性似乎并不是很好.
它虽然号称是组件式开发,但是其前台和后台引擎似乎都没有提供完善的组件模型支持, 只是实现了一些既定的界面组件而已. <br />    1. 其前台的js函数中存在着大量针对数据类型的switch语句,似乎其所能够支持的控件类型已经内置在前台引擎中, 如果我们要增加一种新的界面组件大概需要在各处修改引擎代码, 缺乏一种抽象机制. <br />   
2. 后台ViewModel模型似乎是想构造出一个Component架构来, 但这个模型目前看起来明显没有Echo2这样的组件模型精致,
似乎缺乏一种一致的组件重组机制.  Dorado的ViewModel是有状态的, 通过RPC机制,
它实际上可以独立于系统web层与前台控件交互. <br />    3.
Dataset是Dorado中最重要的数据供体接口, 从它所提供的方法 getField,deleteRecord,
insertRecord, movePrev, moveNext, getPageSize等可以看出,
这明显是绑定到了可分页表格的数据模型上. 实际上整个系统设计似乎都隐含假定了一个Table模型, 例如Validator接口中具有一个函数
ViewField getField(), 这里明确假定了validate只能针对单个字段进行, 而不是属于某个整体组件的.<br />    4. Dorado中所有组件的界面代码生成都是以程序方式进行的, 没有模板机制. 因而增加新的控件的实现时, 需要在后台通过java代码输出一部分界面, 在前台通过js脚本动态更新界面, 工作量相当大.<br />    5. Dorado中界面输出应该是通过Outputter接口来进行 <br />      public interface Outputter{<br />        public String getStartOutput(HttpServletRequest req, Object o)throws Exception;<br />        public String getEndOutput(HttpServletRequest req, Object o) throws Exception;<br />      }<br />     
这里一方面与web层形成了绑定，另一方面它必须在内部完整的生成界面代码之后一次性传入response, 这无疑加重了后台的内存压力.
输出分成了StartOutput和EndOutput大概是为了支持布局组件等容器类组件, 相当于是组件内部可以有一个洞, 这与Jsp
Tag模型是匹配的, 但是这种方式很难以高效率实现界面上的结构融合. <br />    7. Dorado似乎没有直接提供组件的再封装机制, 在现有组件中作局部修正往往需要通过代码方式来进行.例如表格中的性别字段需要显示图片而不是文字, 则需要在Column的onRefresh事件中写入下代码,<br />            if (record.getValue("sex")){<br />        cell.innerHTML = "&lt;img src='images/man.gif'&gt;";<br />        }<br />        else{<br />        cell.innerHTML = "&lt;img src='images/woman.gif'&gt;";<br />        }<br />    这明显已经不是可配置的内容了. 如果我所需要增加的代码是一个复杂的组件, 这里就很难进行处理了. <br />    6. Dorado的技术绑定在了IE浏览器上, 无法兼容其它浏览器, 这有些偏离目前的标准化方向. <br /><br />   
目前的快速开发平台的一个共同特点是集中在单表的CRUD(Create Read Update Delete)上,
可以快速完成单表或主从表的增删改查. 这本也是正确方向,毕竟目前系统开发中的大量工作都是重复性的简单劳动,
但是一般系统设计中为了支持单表操作而在建模的时候引入了对表格模型过强的依赖,  大大降低了系统的可扩展性.
另外现在一般web组件框架的设计往往是模仿桌面开发领域的组件模式， 希望提供完全黑箱式的组件调用方式, 这其实是放弃了web开发的优势. 
实际上借助于xml格式的规范性和简单性, 我们完全可以提供更加强大的结构组件, 并把组件封装的能力开放给普通程序员. </font>
<img src ="http://www.blogjava.net/canonical/aggbug/38732.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-04-02 14:57 <a href="http://www.blogjava.net/canonical/archive/2006/04/02/38732.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]同方ezOne</title><link>http://www.blogjava.net/canonical/archive/2006/04/02/38731.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 02 Apr 2006 06:53:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/04/02/38731.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/38731.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/04/02/38731.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/38731.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/38731.html</trackback:ping><description><![CDATA[
		<p>    <a href="http://www.ezone.com.cn/">http://www.ezone.com.cn</a><br />   
同方这个公司在我的印象中更像是个系统集成商，在软件方面没有什么独特之处。不知道是否是待遇问题，我也未听说同方旗下招揽过什么软件高手。同方最近两年
在软件平台方面花了一些气力，据说有70多个人，干了一两年，将同方以前的项目进行提炼，开发了ezOne平台。现在同方各个事业部开发新项目的时候好像
要求使用该平台，不过可能是涉及到总部和各个部门分钱的问题，下面的人未必有很大的应用积极性。<br />
   
同方的特点是做过大量项目，行业经验多，所以ezOne中提供了很多行业组件。ezOne的一个核心部分是portal服务器，是基于Apache项目组
的Jetspeed修改而来，应该是符合JSR168标准的，所强调的概念也正是应用集成。以前扫过一眼ezOne的代码，感觉质量一般，性能可能会有一
些问题，但编码还算工整。同方握有大量国家资源，应该不至于成为平台产品开发商，开发平台的目的大概还是降低自身开发的难度。其产品倾向于符合标准，中规
中矩，大概很难有什么创新之处。ezOne中很多基础组件都是独立开发的，例如存储层，没有使用hibernate等开源软件。<br /></p>
<img src ="http://www.blogjava.net/canonical/aggbug/38731.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-04-02 14:53 <a href="http://www.blogjava.net/canonical/archive/2006/04/02/38731.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]科诺KA-2</title><link>http://www.blogjava.net/canonical/archive/2006/04/02/38730.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 02 Apr 2006 06:50:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/04/02/38730.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/38730.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/04/02/38730.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/38730.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/38730.html</trackback:ping><description><![CDATA[   <a href="http://www.kenoah.com/">http://www.kenoah.com</a><br />
  
前两天和科诺的研发经理聊了一会，也简单看了一下他们的演示。因为比较匆忙，没有谈到什么实质性的内容，只是有一个粗浅的印象。科诺目前的发展重点还是国
外的外包业务，其网站上相关介绍材料很少，不过据说今年将投入较大的资源在国内公司建设和市场开拓上。<br />
   
科诺产品的特点是代码生成。经过可视化配置之后，可以根据模板生成jsp源代码，程序员可以基于这些代码进行修改。据说遵守一定的规则之后，自动生成的代
码与手写代码是相互隔离的，自动生成的代码可以无限多次生成而不影响手写代码质量，但我未看到演示。科诺生成的页面只支持IE,
不支持Firefox等浏览器。大概是因为其从事的主要是国外外包业务，其界面的美观程度一般。虽然可以修改页面模板来改变界面风格，但从我实际看到的模
板代码而言，重新写一套并不太容易。<br />
   
科诺产品的功能大概是可以完成单表或者主从表的增删改查，并配合一个或者多个业务流程。其工作流引擎据说是符合WFMC规范的，但从实际操作上看，似乎不
是一个通用的工作流引擎。至少给我演示的时候，工作流步骤的每一步，actor所能采取的操作是固定的，如退回，通过等，似乎是为审批定制的。<br />
   
与普元EOS相比，科诺在功能上还是要弱不少。在开发工具上，也显得要简单许多。与普元EOS类似的是，科诺的产品似乎也只是利用工具根据现成的模板制造
固定模式的代码，在设计思想方面并没有什么本质性的突破，与其宣传的组件思想相差甚远。如果要超越自动生成的代码作一些事情，这些平台都无法提供什么有力
的支持。科诺所谓的业务组件似乎就是对table的描述，其设计工具不算太好，至少我没有找到一个汇总视图让我可以看到所有已经配置的字段属性。在设置复
杂字段或者汇总字段方面，科诺的产品也有很多限制，不太灵活。在前台框架方面，科诺写了一个类似于struts的框架，其他就乏善可承了。流程方面的设置
被称为所谓的流程组件，运行时可以通过一个js库在界面上进行展现。不同的业务组件应该可以对应到同一流程组件，这大概就是科诺所谓的组件重用了吧。开发
工程文件以xml格式进行存储，看了一眼，相当复杂，竟然还和SOAP有关系，不知道他们为什么这么设计（符合标准?）。<br />
    在科诺的另外一个印象是，公司里有不少女性程序员在干活。看来至少他们的产品可以由初级程序员掌握并满足美国外包开发的需求。<img src ="http://www.blogjava.net/canonical/aggbug/38730.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-04-02 14:50 <a href="http://www.blogjava.net/canonical/archive/2006/04/02/38730.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]再谈普元EOS中的数据总线</title><link>http://www.blogjava.net/canonical/archive/2006/04/02/38729.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 02 Apr 2006 06:47:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/04/02/38729.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/38729.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/04/02/38729.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/38729.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/38729.html</trackback:ping><description><![CDATA[   前两天一位普元的朋友衣风<a href="http://blog.sina.com.cn/u/1495516693">http://blog.sina.com.cn/u/1495516693</a>在我的blog上留言,谈到对数据总线的不同看法. 我本人并未使用过普元EOS,所做的判断只是基于我个人肤浅的第一印象, 很有可能是不准确的. 不过, 目前我仍然坚持自己对于普元EOS的看法,呵呵.<br />
    <br />
    1. EOS产生的xml描述文件中的大量条目都是EOS自身的结构要求，而与实际业务无关，即EOS描述文件中的有效信息量密度很低.<br />
    衣风认为条目并不是EOS自身的结构要求，而是业务对象的结构描述.
这里我的看法是业务对象应该尽量通过领域(Domain)语言来描述, 领域信息的外在表象应该尽量是卷缩的,而不是展开的,
应该尽量是抽象的而不是实现细节层面上的.例如:<br />
    &lt;function class="test.MyFunctionProvider"&gt;<br />
        &lt;args&gt;<br />
            &lt;arg&gt;<br />
                &lt;name&gt;argA&lt;/name&gt;<br />
                &lt;value&gt;3&lt;/value&gt;<br />
            &lt;/arg&gt;<br />
        &lt;/args&gt;<br />
    &lt;/function&gt;<br />
    以上信息可以描述一个方法调用, 这里的function, args, arg, name,
value等标签的设置都是解析器为了理解该调用的语义而规定的结构元素,这些元素并不属于函数本身.
例如我们可以规定如下的调用格式来简化描述文件而不损失信息,<br />
    &lt;function class="test.MyFunctionProvider"&gt;<br />
        &lt;arg name="argA"&gt;3&lt;/arg&gt;<br />
    &lt;/function&gt;<br />
    而在我们的工作流引擎中, 业务操作的调用以封装后的形式出现<br />
    &lt;BusinessA:DoWorkA argA="3"/&gt;<br />
    通过标签封装之后, 我们在调用的时候所需要提供的信息是最小化的, 每一个涉及到的元素都是有着业务含义的,
而将解析器本身的结构要求隐蔽在封装的标签定义中.此后我们如果更换了实现,而业务需求不变, 则我们的调用处是不会受到影响的. <br />
    现在基于xml语法的文件格式很多, 我们的工作流引擎也采用了xml描述. 但是我们的一个基本观点是,
xml配置文件解析器不应该直接理解文件中所有的标签, 即它只需要理解自身的结构元素, 而为引入Domain知识保留余地.<br />
    <br />
    2. 普元EOS中的结构似乎很难进行有效的扩展。而所谓的xml总线技术更加剧了这一点 <br />
   
衣风认为"正是将XML作为数据传递的总线，才使应用在数据层次上具有了较强的扩展能力"。从面向对象的观点看,
程序中普适性的基本基元是数据与行为的集合体, 而程序模块之间的交互也绝不仅仅是通过数据来进行, 而是往往呈现出一种数据与行为的交织状况.
普元的模型应该包含了大量发生紧密关联的局部元素, 它们应该处在同一进程(状态)空间中, 直接访问对象应该是最简单,最经济,
最完备的信息传递方式,
而"xml节点的表达能力远远超越了普通的数据类型，但充其量也不过是对现有数据的规整的树形表示，并不具有动态计算能力（甚至是最简单的lazy
evaluation）". 实际上对于所谓的总线, 最简单的模型是一个可以动态管理的变量集合, 那么一个Map就足够了.
在集合中我们可以保存各种对象, 比如xml节点, 但是又不限于xml节点. 从建模的角度上说,
把xml节点定义为一级集合元素我认为是不合适的. 通过对象的成员函数, 我们在对象图中可以包含大量的动态计算信息, 例如<br />
     obj.getSomeCalculatedAttribute().getLazyLoadValue()<br />
    这些动态语义在纯数据含义的xml总线技术中不知道如何表达. <br />
    对象图表达数据关联的能力也强于树形结构的xml节点, 例如 obj.getRefObj().getRefObj() == obj, 不知道这样的关联在普元EOS的数据总线中如何表达. <br />
    在并发访问中如果需要同步, 对于对象, 我们可以使用synchronized机制, 但是对于xml节点不知道如何才能有通用的处理方式.  <img src ="http://www.blogjava.net/canonical/aggbug/38729.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-04-02 14:47 <a href="http://www.blogjava.net/canonical/archive/2006/04/02/38729.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]普元EOS</title><link>http://www.blogjava.net/canonical/archive/2006/04/02/38728.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 02 Apr 2006 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/04/02/38728.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/38728.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/04/02/38728.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/38728.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/38728.html</trackback:ping><description><![CDATA[
		<p>     <a href="http://www.primeton.com/">http://www.primeton.com/</a></p>
    普
元软件公司是国内专业的中间件提供商，从国家得到了不少投资，做出来的东西也是相当的庞大。最近普元EOS的宣传和发展的势头都很盛。其宣传材料中屡次提
到“软件的涅磐“这一用语，这明显是一种危言耸听之举，当然这在业内也不算什么新鲜的事情。按照EOS的宣传，"以图形化的构件组装方式“画”出来的软件
无论从结构上、形式上还是开发过程上都堪称简捷而美的软件"。这一提法倒是别开生面。图形化与简洁，与美竟然还存在着这样必然的联系，实在是一种创举。<br />
    
从普元公开的资料来看，EOS的一个鲜明特征是全面基于xml描述，即所谓的xml数据总线。表面上看起来，xml结构内置于系统内核中似乎很时尚，但实
际上，EOS产生的xml描述文件中的大量条目都是EOS自身的结构要求，而与实际业务无关，即EOS描述文件中的有效信息量密度很低。这是一个危险的信
号。EOS的xml描述本身可以看作是一种完全新的编程语言，但这个语言似乎没有什么抽象能力和组合能力，对于关联的表达能力也很弱（到处都是数字
id)。如果直接手工编写，那是一件要死人的事情。只有通过集成开发环境的可视化界面，EOS才呈现出可理解的一面。<br />
    
EOS的概念与Language
Workbench是不同的，其中的结构似乎很难进行有效的扩展。而所谓的xml总线技术更加剧了这一点。xml数据总线其实与面向过程编程类似，只是过
程变成了service，数据变成了xml节点而已。对象与简单数据结构在结构表达上的本质差异就在于对象通过成员函数可以封装动态结构。虽然xml节点
的表达能力远远超越了普通的数据类型，但充其量也不过是对现有数据的规整的树形表示，并不具有动态计算能力（甚至是最简单的lazy
evaluation）。丧失了动态计算能力，就意味着我们很难在系统中动态引入结构，程序中所操纵的结构都需要事前定义出来，这将极大的限制系统的可扩
展性。另一方面，xml节点受限于自身格式，其描述关联的能力也要弱于java对象结构本身。对象通过引用访问相关对象，其隐含意义是对象处于同一地址
（状态）空间中，可以非常自然的保证对象的唯一性并实现同步访问。在跨越状态空间的边界时，xml表示是有意义的，因为我们需要把所有的结构都暴露出来并
加以描述(外在化）。而在状态空间内部，我们需要更加紧致有效的表述方式。<br />
     在具体的实现中，
EOS暴露给程序员的xml操纵API相当的原始，使用起来很繁琐。在前台展示页面中，如果不使用EOS的界面组件，提取数据本身就是一种不小的困难。
EOS的前台展示组件与后台的结合也比较弱，后台改变之后，缺乏有效的手段来检测并保证前后台结构的同步性。所谓的前台构件层似乎只是提供了一些帮助函数
和功能固化的组件，并没有提供什么有效的利于结构抽象和结构重组的机制。<br />
     整个EOS的构架看起来很象是一个monster, 我很难想象它的各个部分如何才能独立的，深入的发展下去。<img src ="http://www.blogjava.net/canonical/aggbug/38728.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-04-02 14:45 <a href="http://www.blogjava.net/canonical/archive/2006/04/02/38728.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]Ajax结构分析</title><link>http://www.blogjava.net/canonical/archive/2006/02/22/32012.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Wed, 22 Feb 2006 12:33:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/02/22/32012.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/32012.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/02/22/32012.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/32012.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/32012.html</trackback:ping><description><![CDATA[<p>Ajax: A New Approach to Web Applications <a href="http://www.adaptivepath.com/publications/essays/archives/000385.php">http://www.adaptivepath.com/publications/essays/archives/000385.php</a><br>Ajax(Asynchronous
JavaScript +
XML)并不是一个革命性的崭新概念（也许根本就不存在突发的革命），它的技术基础在多年之前就已经牢固的建立起来了，在概念层次上的探讨也早就不是一个
新鲜的话题，只是大规模的有深度的应用似乎是最近才开始的。<br>
从广义上说，web应用至少涉及到两个结构，<br>
1. 后台以java语言表达的业务逻辑结构 <br>
2。前台以html语言表达的界面表现结构。</p>
<p>web开发很大一部分工作就是建立这两个结构之间的关系。即我们需要<br>
html &lt;--&gt; java</p>
<p>我
们首先要意识到这两种结构之间并不一定是同构的，即后台数据的组织方式与前台展现时的结构是不同的。同样的数据可以对应于不同的展现结构。这也是所谓
MVC架构实现模型与视图分离的依据。传统上，基于Model2模式的MVC框架中，这两种结构的映射只能在很粗的粒度上进行（即整个页面的粒度上），因
此妨碍了封装和重用。为了进行细粒度的映射，我们必须要拥有细粒度的结构控制能力。而目前最强的结构控制能力存在于javascript/DHTML模型
之中，在js中html的结构可以是一段线性的文本(innerHTML和outerHTML), 可以是层级组织的节点（parentNode,
childNodes),
也可以是按照key组织起来的Map(getElementById)。在不同的情形下，我们可以根据需要选择不同的结构模型。<br>
ajax体系很直接的一个想法就是将所有关于界面表达和控制的结构都推到前台，由控制力最强的js来控制后台数据模型与前台html模型之间的映射。<br>
html &lt;--&gt; js &lt;==&gt; xml &lt;==&gt; java <br>
在ajax
体系中，xml所扮演的角色是js与java之间的翻译通道，它将js中的结构与java中的结构对应起来，这种翻译比html/java之间的映射要简
单的多。其实它甚至可以是一种同构的映射，可以用一种通用的方式来进行，例如结合burlap与buffalo包的功能。结合webservice的一些
思想，js/java之间的映射是可以在函数调用这种细粒度上自动进行的，从而我们最终可以在概念上完成html/java之间的细粒度映射。</p>
				  
             <img src ="http://www.blogjava.net/canonical/aggbug/32012.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-02-22 20:33 <a href="http://www.blogjava.net/canonical/archive/2006/02/22/32012.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]代码复用(reuse</title><link>http://www.blogjava.net/canonical/archive/2006/01/23/29054.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Mon, 23 Jan 2006 15:01:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/01/23/29054.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/29054.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/01/23/29054.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/29054.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/29054.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;
代码复用包括两个方面：概念复用和实现复用。这两者在C++的虚拟函数设计中是合二为一的，结果概念上的模糊往往造成继承机制的滥用。为了复用我们往往在
基类中塞入过多的职责，并在程序中制造了过多的层次。java的interface是纯粹的概念复用机制，实现方面的复用我们一般通过Impls类或者
Utils类来进行，即将代码片断写为静态函数。一般应该避免在类中写特别多的帮助性成员函数，因为成员函数隐含的通过成员变量相关着，比静态函数要更加
难以控制。<br>
&nbsp;&nbsp;&nbsp;
类是一个整体的概念，整体概念失效了，类也就不存在了。从这一点上来说，它未必是比静态函数更加稳定。概念与实现是两个不同层面的东西。实际上它们一般也
是多对多的关系。同一个概念可能换用多种不同的实现，而同一段功能代码也可能在多个类中使用。<br>
&nbsp;&nbsp;&nbsp;
代码复用的意义不仅仅在于减少工作量。实际上复用是对软件的一种真正的检验，而测试仅仅是一种模拟的检验而已。每一次复用都是对代码的一次拷问。在不断使
用中感受到不同使用环境中的各种压力，才能实现概念的不断精化并确保实现的正确性。<br></p>
				  
             <img src ="http://www.blogjava.net/canonical/aggbug/29054.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-01-23 23:01 <a href="http://www.blogjava.net/canonical/archive/2006/01/23/29054.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于DAO和Service</title><link>http://www.blogjava.net/canonical/archive/2006/01/23/29053.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Mon, 23 Jan 2006 14:57:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/01/23/29053.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/29053.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/01/23/29053.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/29053.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/29053.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 我们开发程序的目的是为了完成业务功能, 理想的情况下程序中的每一条语句都应该是与业务直接相关的,
例如程序中不应该出现连接数据库, 读取某个字段等纯技术性的操作, 而应该是得到用户A的基本信息等具有业务含义的操作. dao(data
access object)层存在的意义在于将与数据持久化相关的函数调用剥离出去, 提供一个具有业务含义的封装层. 原则上说,
dao层与utils等帮助类的功能非常类似, 只是更加复杂一些, 需要依赖更多的对象(如DataSource,
SessionFactory)等. 如果不需要在程序中屏蔽我们对于特定数据持久层技术的依赖, 例如屏蔽对于Hibernate的依赖,
在dao层我们没有必要采用接口设计. 一些简单的情况下我们甚至可以取消整个dao层, 而直接调用封装好的一些通用dao操作函数,
或者调用通用的EntityDao类等. <br>
&nbsp;&nbsp;&nbsp; 程序开发的过程应该是从业务对象层开始的, 并逐步将纯技术性的函数调用剥离到外部的帮助类中,
同时我们会逐渐发现一些业务操作的特定组合也具有明确的含义, 为了调用的方便, 我们会把它们逐步补充到service层中. 在一般的应用中,
业务逻辑很难稳定到可以抽象出接口的地步, 即一个service接口不会对应于两个不同的实现, 在这种情况下使用接口往往也是没有必要的. <br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp; 在使用spring的情况下原则上应该避免使用getBean的调用方式, 应该尽量通过注入来获得依赖对象, 但有时我们难免需要直接获取业务对象, 在不使用接口的情况下可以采用如下方式<br>
<br>
&nbsp;&nbsp;&nbsp; class TaskService{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static TaskService getInstance(){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (TaskService)BeanLoader.getBean(TaskService.class);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;
在程序中我们可以直接使用TaskService.getInstance()来得到TaskService对象.通过命名规范的约定,
我们可以从类名推导出spring配置文件中的对象名, 因而不需要使用一个额外的硬编码字符串名. <br>
<br>
<img src ="http://www.blogjava.net/canonical/aggbug/29053.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-01-23 22:57 <a href="http://www.blogjava.net/canonical/archive/2006/01/23/29053.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web程序中的scope</title><link>http://www.blogjava.net/canonical/archive/2006/01/15/28130.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 15 Jan 2006 14:35:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/01/15/28130.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/28130.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/01/15/28130.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/28130.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/28130.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;
jsp模型为web程序提供了page/request/session/application这四个基础性的变量域.
这种变量域的划分很大程度上是纯技术性的, 与我们的业务应用中需要的scope支持相去甚远. 当我们把业务对象的生命周期映射到这些变量域的时候,
经常出现不适应的情况. 例如我们可能被迫选择把与某项业务相关的所有数据放置在session中并在各处硬编码一些资源清理代码.
为了实现与愈来愈复杂的应用开发的契合, 我们需要能够在程序中定义与应用相关的变量域并实现对这些变量域的管理,
即我们需要一种自定义scope的支持而不是使用几个固定的scope. <br>

&nbsp;&nbsp;&nbsp; JBoss的Seam项目<a href="http://www.jboss.com/products/seam">http://www.jboss.com/products/seam</a> 中引入了一种所谓declarative application state management的机制<br>

&nbsp;&nbsp;&nbsp; <a href="http://blog.hibernate.org/cgi-bin/blosxom.cgi/Gavin%20King/components.html">http://blog.hibernate.org/cgi-bin/blosxom.cgi/Gavin%20King/components.html</a>,
其中的关键是增加了business process和conversation这两个应用直接相关的scope, 它们都是可以根据需要自由创建的.
business process context使用jBPM支持long running的状态保持. 而conversation
context是对session使用的一种精细化, 与beehive项目中的page flow所需的scope支持非常类似 <a href="http://beehive.apache.org/docs/1.0m1/pageflow/pageflow_overview.html">http://beehive.apache.org/docs/1.0m1/pageflow/pageflow_overview.html</a>. 但目前seam中的scope支持仍是非常原始的, 不支持嵌套的context, 这意味着对于复杂应用尚无控制和管理能力.<img src ="http://www.blogjava.net/canonical/aggbug/28130.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-01-15 22:35 <a href="http://www.blogjava.net/canonical/archive/2006/01/15/28130.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>xpath selector vs. css selector</title><link>http://www.blogjava.net/canonical/archive/2006/01/08/27196.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Sun, 08 Jan 2006 15:21:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2006/01/08/27196.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/27196.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2006/01/08/27196.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/27196.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/27196.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 在无侵入性的前台页面控件设计方案中, 我们需要一种简便的方法迅速定位页面中的某一节点(dom
node). 使用xpath是非常诱人的一个技术选择, 但是在实际使用中, 我们却发现xpath并不是那么方便. xpath的能力非常强大,
它支持绝对定位, 例如//input[@id='3'], 也支持相对定位, 例如 ./input[0], 甚至支持根据节点内容定位,
例如//a[contains(., 'partial text')]. <br>
&nbsp;&nbsp;&nbsp; 问题是在一个复杂的界面控件中, html节点本身的结构与界面展现结构并不是一致的,例如一个特定效果的边框可能需要多个html元素互相嵌套才能够实现, 因此xpath的相对路径选择能力往往派不上用场(除非是提供<a href="http://www.backbase.com/">http://www.backbase.com/</a>那
样的界面抽象层), 而根据内容定位的方式过于灵活, 难以维护一个稳定的概念层. 相比较而言,
css的选择符所提供的节点定位方式要比xpath更加简单直观, 它的适用性也早已在大量的实践中得到了证实.
基于css选择符实现behaviour机制是一种更加可行的方案. 参见 <a href="http://prototype.conio.net/">http://prototype.conio.net/</a><img src ="http://www.blogjava.net/canonical/aggbug/27196.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2006-01-08 23:21 <a href="http://www.blogjava.net/canonical/archive/2006/01/08/27196.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]UnitTest:语义校验</title><link>http://www.blogjava.net/canonical/archive/2005/12/28/25795.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Wed, 28 Dec 2005 14:34:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/12/28/25795.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/25795.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/12/28/25795.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/25795.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/25795.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;
单元测试随着agile的流行已经家喻户晓了，这正反映了软件的一个本质特征：软件是Man-Made的，而人是不可靠的。软件出错的高频率必然导致控制
间隔的缩短。我最早是在编写matlab程序的时候独立的发现了单元测试的作用。因为matlab是弱类型的，横纵矢量也不区分，很容易犯错误，我就为每
一个matlab函数编写了测试脚本，约定了命名规范为xxx_test.m, 在测试的时候通过
can_assert来做出判断而不是输出变量内容进行人工检查。
每次作了修改的时候，运行一下can_test_all.m就自动搜索测试脚本并运行一遍。 后来xp出现了，
我也第一次听说了单元测试这回事，看来英雄所见略同吧 ^_^<br>
&nbsp;&nbsp;
单元测试可以看作是对编译器的补充。编译器只能进行语法检查（形式），而单元测试可以进行语义检查(内容），它其实维护了程序的一个语义框架。如果单元测
试程序编写出来了，即使一行业务实现代码也没编写，我们手中也已经拥有了一笔宝贵的财富，因为程序的语义已经在某种意义下确定下来了。重构一般是在维护单
元测试不变的情况下进行的。即我们发现在维护语义不变量的情况下，系统具有相当的调整余地。<br>
&nbsp;&nbsp;
坚持单元测试的另一个好处是它倾向于良好分离的模块，因为高内聚低耦合的模块才更容易进行测试。为了测试，我们会在不知不觉中在对象职责的分离上投注更多
的心力。在witrix平台中，虽然基于EasyMock提供了mock支持，在实际中却很少使用，因为模块功能一般很独立，不需要复杂的mock对象，
而对于一般的对象，eclipse有代码生成功能，可以非常轻易的生成简单的测试对象。<br>
&nbsp;&nbsp; 虽然JUnit非常流行，我们的单元测试也是基于JUnit进行的，但是我们还是进行了一个简单的封装，将JUnit框架的特定要求与具体测试代码剥离开来。具体的，测试类从<br>
&nbsp;&nbsp; test.UnitTest继承，而不是从JUnit的TestCase继承。使用Debug.check()来做判断，而不是JUnit的assertEquals等。<br>
&nbsp;&nbsp; class MyTest extends UnitTest{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public MyTest(String caseName){ super(caseName); }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void testMy(){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyObject my = new MyObject();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object value = myObject.myFunc();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Debug.check(value.equals("aa"));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 可以同时提供一个出错消息<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Debug.check(value.equals("aa"),"myFunc return invalid : "+value);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void main(String[] args){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 不需要IDE或者其他外部的支持就可以直接调用测试代码，将会自动输出运行时间等<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UnitTest.exec(new MyTest("testMy"));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp; }<br>
</p>
				  
             <img src ="http://www.blogjava.net/canonical/aggbug/25795.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-12-28 22:34 <a href="http://www.blogjava.net/canonical/archive/2005/12/28/25795.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过继承构造业务对象环境</title><link>http://www.blogjava.net/canonical/archive/2005/12/06/22796.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Tue, 06 Dec 2005 14:33:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/12/06/22796.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/22796.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/12/06/22796.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/22796.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/22796.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 现在很多设计中推崇接口和依赖注入(dependency
injection)，而不倾向于采用继承机制来构造程序结构。但很多时候作为一种简便而廉价的封装方法,继承仍然是不可或缺的.
例如与一些Engine打交道的时候,需要实现某些特定的接口. 在osworkflow中, 我们需要实现FunctionProvider接口, <br>
&nbsp;&nbsp;&nbsp;&nbsp; interface FunctionProvider{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException;<br>
&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; 在Quartz中需要实现Job接口<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; interface Job{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void
execute(JobExecutionContext context) throws JobExecutionException;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; 这些接口是一种技术性的要求, 它们表示了代码生存所依赖的技术环境. 为了屏蔽这种对于外部引擎的依赖, 我们可以简单的选择实现一个基类,<br>
&nbsp;&nbsp;&nbsp; abstract class AbstractFunction implements FunctionProvider,Runnable{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map transientVars;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map args;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PropertySet ps;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public final void execute(Map transientVars, Map args, PropertySet ps){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.transientVars = transientVars;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.args = args;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.ps = ps;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public Object getPersistVar(String name){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ps.getAsActualType(name);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setPersistVar(String name, Object value){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ps.setAsActualType(name,value);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void removePersistVar(String name){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ps.remove(name);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;
在派生类中我们只要使用getPersistVar等函数就可以回避对于osworkflow特有的PropertySet类的依赖，而只在概念上需要一
个对象的持久化机制．当我们把业务代码从osworkflow移植到其他工作流引擎的时候，　只需要改变一下基类即可．我们可以在基类中引入更加特殊的假
设，<br>
&nbsp;&nbsp;&nbsp; abstract AbstractBusinessFunction extends AbstractFunction{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public BusinessObject getBusinessObject(){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return transientVars.get("businessObject");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void commonBusinessOp(){ ... }<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp;
AbstractBusinessFunction提供的可以是一个完整的业务对象环境，　我们在派生类中的所有代码都可以是与业务直接相关的，而与具体
的技术实现无关（例如业务变量是存放在transientVars中还是存放在args中）<br>
<br>
&nbsp;&nbsp;&nbsp; class BusinessFunction extends AbstractBusinessFunction{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void run(){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BusinessObject bo = getBusinessObject();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo.methodA();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; commonBusinessOp();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;
对于我们来说实际有意义的是在派生类中所书写的代码，基类仅仅提供一个环境而已．无论我们使用Ioc注入业务变量还是从transientVars中主动
获取业务变量，都是与我们的业务操作无关的．　实际上在理论上我们希望整个基类都可以是注入的（包括业务变量和业务操作），在泛型编程中这对应于所谓的
policy class. <br>
<br>
<img src ="http://www.blogjava.net/canonical/aggbug/22796.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-12-06 22:33 <a href="http://www.blogjava.net/canonical/archive/2005/12/06/22796.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]tag技术</title><link>http://www.blogjava.net/canonical/archive/2005/12/02/22301.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Fri, 02 Dec 2005 14:59:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/12/02/22301.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/22301.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/12/02/22301.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/22301.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/22301.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; tag在国内java社区并不算流行，这在很大程度上是因为jsp
tag的设计失误造成的。但在整个开发业界内，tag已经成为一种广泛应用的技术。微软的dotNet服务器端极端依赖tag技术，而在浏览器端IE的
behaviour, htc也独立的发展起来。Longhorn的XAML，
Firefox的XUL无一例外的依赖于可自定义的tag。java社区的JSF, SiteMesh, Tiles
等等，不可尽数。有些人在前台通过给html原有元素增加自定义属性，然后通过javascript去解释的做法，也是一种element
enhance概念的变种。至于FreeMarker这种模板语言，明明类似于tag技术，偏偏不采用xml语法，简直是自找麻烦。<br>
&nbsp;&nbsp;&nbsp;
这里最关键的地方就是自定义tag可以实现抽象层次的提升，是一种类似于函数封装的机制，从而实现概念的分离和明确化。基于tag可以实现页面元素的组件
化，加上xml语法的可理解性，表达能力以及无与伦比的集成能力，使得tag技术可以超越VB等组件开发环境（想想集成别人的组件代码难还是集成别人的
xml描述文件难）。自定义tag提供的抽象能力不仅仅是面向对象的，而且是类似AOP的，这些都极大的辅助了我们的思考和设计。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;cocoon使用管道技术也构造了某种tag机制，但是它的效率很成问题。从数学上说多个处理函数 g, h, k可以通过函数组合(composition)构成新的函数f</p>
<p>&nbsp;&nbsp;&nbsp; f(data) = g&nbsp;*&nbsp;h * k(data)&nbsp;</p>
<p>这是所谓函数式语言强大能力的源泉。cocoon处理的时候从k(data)开始，处理完毕之后调用h, 即函数是从右向左结合的。如果我们保证处理函数满足左结合律，则g*h*k就可以预编译为f, 从而解决性能问题，这正是witrix平台中tpl技术所采用的方案。</p>
<img src ="http://www.blogjava.net/canonical/aggbug/22301.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-12-02 22:59 <a href="http://www.blogjava.net/canonical/archive/2005/12/02/22301.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> AjaxAnywhere</title><link>http://www.blogjava.net/canonical/archive/2005/11/23/21184.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Wed, 23 Nov 2005 13:53:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/23/21184.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/21184.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/23/21184.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/21184.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/21184.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; <a href="http://ajaxanywhere.sourceforge.net/index.html">http://ajaxanywhere.sourceforge.net/index.html</a><br>
&nbsp;&nbsp;&nbsp; AjaxAnywhere利用JSP标签把Web页面标注出可以动态装载的区域, 可以直接把任何JSP页面转化为AJAX感知组件而不需要进行复杂的Javascript编码.<br>
&nbsp;&nbsp;&nbsp; &lt;script&gt; ajaxAnywhere.getZonesToLoad = function(url){ return "countriesList"; } &lt;/script&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;select size="10" name="language" onchange="ajaxAnywhere.submitAJAX();"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%@ include file="/locales_options_lang.jsp"%&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/select&gt;<br>
<br>
&nbsp;&nbsp;&nbsp; &lt;aa:zone name="countriesList"&gt;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;select size="10" name="country" &gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%@ include file="/locales_options_countries.jsp"%&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/select&gt;<br>
<br>
&nbsp;&nbsp;&nbsp; &lt;/aa:zone&gt;<br>
&nbsp; &nbsp;<br>
&nbsp;&nbsp; AjaxAnywhere的这种做法与witrix平台中的ajax方案有些类似, 例如<br>
&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp;
&lt;select onchange="new
js.Ajax().setObjectEvent('changeLanguage').setParam(this).setTplPart('countriesList').replaceChildren('countriesList')"&gt;
...&lt;/select&gt;<br>
<br>
&nbsp;&nbsp;&nbsp; &lt;div id="countriesList"&gt;<br>
&nbsp;&nbsp; &lt;tpl:define id="countriesList"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ....<br>
&nbsp;&nbsp; &lt;/tpl:define&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;/div&gt;<br>
<br>
&nbsp;&nbsp;&nbsp;
但是在AjaxAnywhere的方案中, 后台jsp页面总是要完整运行的, 它通过servlet filter机制缓存所有的jsp输出,
而aa:zone标签则把自己的bodyContent运行后的结果保存在request的attribute中, 最后servlet
filter根据调用参数决定返回那些zone的运行结果. 而在witrix平台中的方案中, 只有指定的tplPart才会被运行,
其他部分完全被忽略. 这种差异的根源在于Jsp Tag技术本身的局限性. Jsp Tag的设计是非常原始的,
基本上就是在字符串层面上进行操作, 在运行的时候缺乏对页面结构强有力的控制. 实际上, 在我看来, 所有基于jsp tag的技术都受制于jsp
tag的先天的局限性, 很难有深度的发展, 包括JSF技术.<br>
&nbsp;<img src ="http://www.blogjava.net/canonical/aggbug/21184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-23 21:53 <a href="http://www.blogjava.net/canonical/archive/2005/11/23/21184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]Quartz 任务调度</title><link>http://www.blogjava.net/canonical/archive/2005/11/22/21011.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Tue, 22 Nov 2005 09:55:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/22/21011.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/21011.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/22/21011.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/21011.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/21011.html</trackback:ping><description><![CDATA[<p>quartz是一个高质量的任务调度软件包。其主要组成部分为:<br>
</p>
<p>Scheduler接口: quartz的执行线程，它根据Trigger决定调度时刻，根据JobDetail的说明实例化并运行Job<br>
</p>
<p>JobDetail类: 可持久化的任务描述信息。任务虽然分组，但是仅用作管理标示，任务之间并无实质性关联, 例如无法定义job chain。<br>
</p>
<p>Trigger类:任务的调度策略。这里的特点是调度策略与任务描述分开，调度策略和任务描述都可以分别在Scheduler注册，然后再关联起来。JobDetail与Trigger的关系是一对多。<br>
</p>
<p>JobDataMap: 将任务的运行时可持久化状态信息从JobDetail类中分离出来<br>
</p>
<p>Job接口: 任务的执行代码<br>
</p>
<p>StatefulJob接口: 无状态任务对应的JobDataMap可以认为是只读的,而有状态的任务在多次执行过程中保留对JobDataMap所作的修改,一个后果是有状态任务无法被并发执行。<br>
</p>
<p>JobExecutionException类: 可以通过JobExecutionException调整调度程序的下一步动作<br>
Calendar接口: 用于从trigger的调度计划中排除某些时间段，例如假期等。</p>
<p>以上几个部分的交互关系如下：<br>
class JobImpl implements Job{<br>
&nbsp;&nbsp;&nbsp; public void execute(JobExecutionContext context) throws JobExecutionException{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobDetail detail = context.getJobDetail();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JobDataMap dataMap = detail.getJobDataMap();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp; }<br>
}</p>
<p>scheduler.addCalendar("myHolidays", holidayCalendar, false);<br>
trigger.setCanlendarName("myHolidays");</p>
<p>JobDetail jobDetail = new JobDetail(jobName, jobGroupName, JobImpl.class);</p>
<p>scheduler.scheduleJob(jobDetail, trigger);</p>
<p>JobDetail可以设置如下属性:<br>
1. Durability: non-durable的任务当不再与任何active trigger关联的时候将会从scheduler中被自动删除。<br>
2. Volatility: volatile的任务在scheduler的两次启动之间不会被持久化<br>
3. RequestsRecovery: 如果在执行过程中程序意外崩溃，标记为"request recovery"的任务在scheduler重起之后将会被再次执行，此时JobExecutionContext.isRecovering()返回true.</p>
<p>Trigger可以设置如下属性:<br>
1. misfireInstruction: 设定当trigger错过了触发时刻的时候需要采取的处理策略</p>
<p>SimpleTrigger按照固定的时间间隔进行触发<br>
startTime, endTime, repeatCount, repeatInterval</p>
<p>CronTrigger按照日历间隔进行触发<br>
seconds minutes hours day-of-month month day-of-week</p>
<p>在quartz内部，QuartzSchedulerThread按照时间顺序选择trigger（没有任务优先级的概念）, 然后在JobRunShell中运行Job。</p>
<p>JobRunShell中的调用顺序如下:</p>
<p>TriggerListener.triggerFired<br>
&nbsp;&nbsp;&nbsp; Called by the Scheduler when a Trigger has fired, and it's associated JobDetail is about to be executed.</p>
<p>TriggerListener.vetoJobExecution<br>
&nbsp;&nbsp;&nbsp; Called by the Scheduler when a Trigger has fired, and it's associated JobDetail is about to be executed.</p>
<p>JobListener.jobToBeExecuted<br>
&nbsp;&nbsp;&nbsp; Called by the Scheduler when a JobDetail is about to be executed (an associated Trigger has occured).</p>
<p>Job.execute<br>
&nbsp;&nbsp;&nbsp; Called by the Scheduler when a Trigger fires that is associated with the Job. <br>
&nbsp; <br>
JobListener.jobWasExecuted<br>
&nbsp;&nbsp;&nbsp; Called by the Scheduler after a JobDetail has been
executed, and be for the associated Trigger's triggered(xx) method has </p>
<p>been called.</p>
<p>Trigger.executionComplete<br>
&nbsp;&nbsp;&nbsp; Called after the Scheduler has executed the
JobDetail associated with the Trigger in order to get the final
instruction </p>
<p>code from the trigger. </p>
<p>TriggerListener.triggerComplete<br>
&nbsp;&nbsp;&nbsp;&nbsp; Called by the Scheduler when a Trigger has
fired, it's associated JobDetail has been executed, and it's
triggered(xx) </p>
<p>method has been called.</p>
SchedulerListener.triggerFinalized [if(trigger.getNextFireTime() == null)]<br>
&nbsp;&nbsp;&nbsp;&nbsp; Called by the Scheduler when a Trigger has reached the condition in which it will never fire again. <img src ="http://www.blogjava.net/canonical/aggbug/21011.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-22 17:55 <a href="http://www.blogjava.net/canonical/archive/2005/11/22/21011.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代码习惯</title><link>http://www.blogjava.net/canonical/archive/2005/11/17/20214.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Thu, 17 Nov 2005 03:55:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/17/20214.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/20214.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/17/20214.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/20214.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/20214.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 新手总是有很多不好的代码习惯. 最常见的一个是不使用临时变量.例如 <br>
&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;myList.size();i++){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; otherList.get(i).getSomeVar().getName();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; otherList.get(i).getSomeVar().getValue();<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; 这种做法有如下后果:<br>
&nbsp;&nbsp;&nbsp; 1. 代码冗长, 容易出错, 例如循环体中的某个i写成了j<br>
&nbsp;&nbsp;&nbsp; 2. 函数调用终究是要耗费时间的, 在一个循环体中的调用往往对性能有可见的影响. 特别是当函数动态装载数据的时候, 例如每次调用该函数都查询数据库, 这种不使用临时变量的方法将会为系统留下性能隐患.<br>
&nbsp;&nbsp;&nbsp; 3. 一条很长的语句如果不是为流式调用而设计的, 则这种调用方式会影响到我们的调试工作. 例如
当某个中间步骤返回空指针时, 程序会抛出NullPointerException异常, 而我们得到的信息只是某一行存在空指针异常,
但是无法定位到具体是哪个步骤. 当某个中间步骤返回的值不是null但也不是我们所期望的值的时候, 我们同样难以诊断出具体出错的步骤.
使用临时变量将会为调试提供便利<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i,n=myList.size();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0;i&lt;n;i++){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyVar var = otherList.get(i);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var.getName();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var.getValue();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在需要的时候我们可以在出错语句处加上断点, 或者直接输出可疑的变量值.<br>
&nbsp;&nbsp;&nbsp; 4. 长语句不利于抽象出子函数. 例如在第二种方式中我们抽象出子函数的难度比第一种方式小<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void processVar(MyVar var){<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var.getName();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var.getValue();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; 造成这些习惯的原因很耐人寻味, 我猜想缺乏抽象能力似乎是最基本的原因, 毕竟为变量起一个名字也是最简单的抽象步骤之一.<br>
<br>
<img src ="http://www.blogjava.net/canonical/aggbug/20214.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-17 11:55 <a href="http://www.blogjava.net/canonical/archive/2005/11/17/20214.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]EasyCalendar:一维随机游走</title><link>http://www.blogjava.net/canonical/archive/2005/11/16/20142.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Wed, 16 Nov 2005 11:28:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/16/20142.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/20142.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/16/20142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/20142.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/20142.html</trackback:ping><description><![CDATA[<p><font color="#000000" size="3">在时间轴上定位一般比较麻烦，我们可以编写大量的get函数来得到特殊时间点，如
getFirstDayOfMonth(int year,int month), getFirstDayOfNextMonth(int
year, int month)，这不如采用如下正交化的流式设计。<br>EasyCalendar cal = </font></p>
<font color="#000000" size="3">&nbsp;&nbsp;&nbsp; new EasyCalendar().toYear(2001).toMonth(1).toFirstDayOfMonth().toFirstDayOfWeek();</font><img src ="http://www.blogjava.net/canonical/aggbug/20142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-16 19:28 <a href="http://www.blogjava.net/canonical/archive/2005/11/16/20142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]数据仓库建模</title><link>http://www.blogjava.net/canonical/archive/2005/11/15/19835.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Tue, 15 Nov 2005 04:29:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/15/19835.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/19835.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/15/19835.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/19835.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/19835.html</trackback:ping><description><![CDATA[<font color="#000000" size="3">关系数据库的关键之处在于关系的分解，在数据库中只定义了数据之间的两两关系，与应用相
关的更复杂的数据关系需要在运行时通过动态join来构造出来，即这些关系储存在程序中而不是数据库中。实际上，关系数据库的一个隐含的假定是数据之间很
少关联，而在实际应用中单表和主从表也正是最常出现的情况。当一个应用频繁需要大量表的连接操作的时候，往往意味着关系数据模型的失效，此时我们将不得不
放弃数据的无冗余性，需要通过预连接来构造实例化视图(Material View)，将数据之间的复杂关系固化并明确定义出来。
在数据仓库里，抽象的讨论star schema和snowflake schema哪个更优越是一个毫无意义的问题。
应该聚合到什么程度，需要根据数据应用的具体情况而定。<br>&nbsp;&nbsp;&nbsp;
关系数据库本身定义的是数据之间的两两关系，缺乏一些全局数据访问手段。而数据仓库的一个基本概念是数据空间，即可以通过全局坐标来直接访问数据，而不是
通过两两连接来访问数据。在数据仓库中最重要的就是时间维度，因为这是所有数据所共享的一个坐标维度。我们可以将两个发生在同一时间点上的数据直接并列在
一起，而无论它们之间是否定义了关联(relation)。<br>&nbsp;关系数据库的基本数据访问模式如下：<br>&nbsp;select 属性列表&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;from 表A, 表B<br>&nbsp;where 表A.data_id = 表B.id<br>&nbsp;and 表B.attr = 'A'<br>&nbsp;在数据仓库中 " from 表A, 表B where 表A.data_id = 表B.id "这一部分将多个多个数据表和表之间的关联条件放在一起定义为所谓的主题。<br>&nbsp;而 表B.attr = 'A' 这一部分就从where子句中分离出来作为坐标条件。<br>&nbsp;&nbsp;&nbsp; 在数据仓库中建立时间坐标有两种方式，对于发生在时间点上的事件我们直接建立点坐标，通过his_date字段来表示，而对于延续一段时间的状态数据，我们可以建立区间坐标，通过from_date和to_date两个字段来表示。</font><img src ="http://www.blogjava.net/canonical/aggbug/19835.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-15 12:29 <a href="http://www.blogjava.net/canonical/archive/2005/11/15/19835.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]xml db vs RDB</title><link>http://www.blogjava.net/canonical/archive/2005/11/15/19831.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Tue, 15 Nov 2005 04:23:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/15/19831.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/19831.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/15/19831.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/19831.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/19831.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; 关系数据库的理论基础是集合论，而集合的基本定义就是不重复的一组元素。而xml数据库方面尚缺乏相应的理论来消除数据冗余性。<br>
&nbsp;&nbsp;
关系数据库能够成功的另外一个重要原因是它采用平面表形式，而应用中大量使用的正是平面表，所以数据库表在很多时候是数据的最适表现形式，使用xml表达
只会增加不必要的复杂性。平面表的基本假设是所有条目的结构都是一样的（具有一个header），而xml表示形式本身不存在这样的假定，因此很多时候无
法根据数据的shape来做有效的优化。当然xml
schema等技术正在快速发展的过程中，当相应的元数据描述和使用技术逐渐成熟之后，xml的处理方式会得到本质的提高。<br>
&nbsp;&nbsp; xml技术是目前元语言的代表，它最重要的技术优势在于它是人与机器都能轻易理解的语言，是人机共享的信道!
目前它并不适合在应用程序中表达复杂的多维关联。特别是目前多数操纵xml的API都是面向文档的，所存取的数据类型都是字符串，更造成了程序应用上的困
难。<br>
<br>
<img src ="http://www.blogjava.net/canonical/aggbug/19831.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-15 12:23 <a href="http://www.blogjava.net/canonical/archive/2005/11/15/19831.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]jsp tag的七宗罪</title><link>http://www.blogjava.net/canonical/archive/2005/11/15/19830.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Tue, 15 Nov 2005 04:21:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/15/19830.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/19830.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/15/19830.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/19830.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/19830.html</trackback:ping><description><![CDATA[一个技术的成功，在于最终占据了某个概念。当我们应用到此概念的时候，首先想到的就是这个技术实现，久而久之，形成一个自我证明的过程。而有些技术却是在
其位无能谋其政，实在是让人不得不为它扼腕叹息呀。jsp tag正是这样一种技术。有些人认为jsp
tag只是jsp的一种扩展，只是一种syntax suger, 这正反映了此技术所面临的一种困境。这里指出一些jsp
tag的设计缺陷，并无贬低这种技术的意图，只是希望抛砖引玉，引发大家对这种技术改进的探讨。 <br>
引用: <br>
jsp tag是服务器端的扩展标签机制，它是一系列java服务器端技术的基础。但其设计之初的几个重大缺陷已经使得这种技术不堪重负。 &nbsp;<br>
<br>
对比dotNet平台我们可以知道，需要一种后台标签机制，jsp
tag是唯一的标准（JSF等机制都依赖于此)，可它的设计给所有希望基于它开发的开发人员造成了巨大的困扰。实际上我对这个技术感到很失望，当然我们提
出了相应的替代方案。在我们的开发框架中使用的是重新设计的一套与网络无关的xml动态标签机制。我的观点是基于jsp
tag技术，无法开发出与dotNet的便捷程度相当的服务端技术，所以这是它作为标准的罪过。jsp
tag不应该是jsp的补充，它搭上了xml这条大船，应该去走自己的路，而不应该成为应用上的鸡肋。 <br>
引用: <br>
1. jsp tag与jsp 模型紧密绑定，使得业务逻辑很难抽象到tag中。而且脱离了jsp环境，在jsp tag上的技术投资将一无是处。 &nbsp;<br>
<br>
这里说业务逻辑可能是有些不妥，容易引起误解。因为我的工作做在中间件层，所以我的原意是基于jsp
tag开发一系列的扩展技术，比如缓存等。我们的xml标签技术是与jsp模型无关的，在前台用于界面渲染，在后台用于工作流描述。而且很方便的就可以与
其它xml技术结合，比如集成ant。 <br>
<br>
引用: <br>
2. jsp tag的编码逻辑非常繁琐, 特别是写loop和容器类标签的时候。在2.0之前不支持从tag本身产生tag更是应用上的主要障碍。 &nbsp;<br>
<br>
这绝对是个重大问题，试问多少人自己去开发jsp tag呢，多半是用用别人的成品。编制困难其实就是否定了界面元素的重用。很多人推崇Tapestry, 其实如果jsp tag技术方便一点，何必建立一个完全不同的模型呢。 <br>
<br>
引用: <br>
3. 使用将xml标签的属性直接映射到对象属性的方法造成tag对象是有状态的，不得不通过丑陋的pool机制来解决性能问题。 <br>
而且性能问题直接限制了大量小标签的使用。 &nbsp;<br>
<br>
这是一个现实的困难，一个系统设计师必须考虑。 <br>
<br>
引用: <br>
4. jsp tag是一种完全动态化的设计，大量可以在编译期进行的优化都无法进行，基本上所有的运算都是在运行期发生，限制了性能的提高。 &nbsp;<br>
<br>
我们的xml标签技术是先编译再运行的，加上无状态设计，在性能上可以得到控制。我的朋友hotman_x是个C++和js高手，在他的强烈要求下，我们的xml标签还增加了一个多次编译的机制。 <br>
<br>
引用: <br>
<br>
5. 虽然最近的版本已经支持xml格式，但对于xslt等的集成很不到位，例如现在无法使用xslt对jsp文件进行界面布局。 <br>
<br>
最简单的 <br>
&lt;web:template src="test.tpl" xslt="layout.xslt" /&gt; <br>
&lt;web:mytag xdecorator="face.xslt"&gt; <br>
... <br>
&lt;/web:mytag&gt; <br>
<br>
引用: <br>
6. jsp tag要求使用自定义标签名，而无法对已经存在的html标签进行enhance, 造成无法方便的在可视化编辑器中进行编辑。 &nbsp;<br>
<br>
Tapestry就认为它比较好。我们的xml标签机制也支持属性扩展。 <br>
<br>
引用: <br>
7. EL表达式竟然不支持调用对象函数 <br>
<br>
很多人因此觉得OGNL比较好。我们的机制中是对EL做了一定的增强。我不喜欢OGNL, 过于复杂了。<br>
<br>
<img src ="http://www.blogjava.net/canonical/aggbug/19830.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-15 12:21 <a href="http://www.blogjava.net/canonical/archive/2005/11/15/19830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[导入]JMX技术</title><link>http://www.blogjava.net/canonical/archive/2005/11/14/19738.html</link><dc:creator>canonical</dc:creator><author>canonical</author><pubDate>Mon, 14 Nov 2005 09:01:00 GMT</pubDate><guid>http://www.blogjava.net/canonical/archive/2005/11/14/19738.html</guid><wfw:comment>http://www.blogjava.net/canonical/comments/19738.html</wfw:comment><comments>http://www.blogjava.net/canonical/archive/2005/11/14/19738.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/canonical/comments/commentRss/19738.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/canonical/services/trackbacks/19738.html</trackback:ping><description><![CDATA[JMX在技术上的需求可以说是将管理功能从功能性接口中分离出来。<br>
例如一个缓存接口<br>
interface ICache{<br>
&nbsp;&nbsp;&nbsp;&nbsp; Object get(Object key);<br>
&nbsp;&nbsp;&nbsp;&nbsp; void put(Object key, Object value);<br>
}<br>
但一个具体实现类可能有很多参数可以调整，如缓存的最大尺寸等。这些可配置参数一般与具体实现紧密相关，即与实例相关，而不直接涉及到所要实现的功能。例如实现类可以具有setMaxSize()和getMaxSize()方法。<br>
如
果这些配置方法在功能接口中定义，就会造成功能接口的臃肿和不必要的与实现方法之间的依赖。如果直接调用实现类的方法，只能使用reflection，
但是java class作为元数据所承载的信息量有限，需要外部定义一个规范来补充信息。JMX就是这样的一种规范。<img src ="http://www.blogjava.net/canonical/aggbug/19738.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/canonical/" target="_blank">canonical</a> 2005-11-14 17:01 <a href="http://www.blogjava.net/canonical/archive/2005/11/14/19738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>