最近参与了一个严重依赖EJB技术,针对某特定领域的软件产品。由于该领域的业务逻辑种类复杂繁多,UI层无法做到非常简单,同时数据的采集、提交和表现也非常复杂,因此该产品使用了CS架构,通过一个胖客户端连接EJB中的业务逻辑接口,然后由EJB负责调用下层的DAO等完成处理过程。
由于EJB本身就是重量级的侵入型框架,在一定程度上阻碍了面向对象设计,同时开发人员对EJB接口功能划分的问题也并没有足够重视,只是本着“先运行再重构”的简单想法进行了接口功能粒度的划分。
在开发初期中,因为涉及到的业务量较小,因此基本上若客户端需要某个功能,EJB层肯定有相应的功能接口及其实现。换而言之,EJB层本身就不是面向对象的,所有的功能都零散地分布在各个EJB中。例如一个叫做Customer的EJB提供了客户购买产品、退货、更换等逻辑的实现,一个叫做Product的EJB提供了产品定义、价格定义等逻辑的实现。
当软件开发进行到后期的时候,由于业务量越来越大,各个EJB也变得越来越臃肿与庞大,一个EJB里面常常塞满了看起来差不多,但又不完全一致的方法——整个EJB层成为一个包罗反象、无所不能却又混乱不堪的怪物。
幸好,由于有完备的文档支持,整个项目没有失控,各个EJB虽然越来越大,越来越“面向过程”,但整体的功能实现还是得到了保证。最终项目验收的时候,虽然整个软件不“很好看”,但也在功能、速度和成本方面达到了基本要求。
漫长的维护期开始了……
经过这次不能说成功或失败的开发经历后,我有了一点想法:
1.使用EJB这种侵入型框架时,一定要先对业务进行细分,将各个大功能项划分开。
2.在功能细分的基础上,建立相应的业务对象模型,每个业务对象负责一类事务的处理。例如上文中的CustomerBean类其实应该作为一个独立的业务对象存在,而不是作为一个被随意调用的EJB存在。
3.客户端调用EJB时,不是对具体功能的调用,而是通过转发的方式,对业务对象进行调用。客户端只是简单的将参数传递给EJB,然后由EJB负责业务对象的初始化(或以其他形式得到业务对象),然后将参数传递给业务对象,生成结果后再返回给客户端。EJB在这里只是起转发的作用。
这样做可以解决EJB层责任混乱的问题。
在以前的设计中,EJB层负责对传入数据的解释,然后调用所有的业务逻辑,最后对生成结果进行包装,返回给客户端。而且整个过程由于是采用硬编码的形式写在了一个函数中,因此重用的可能性不大。
在新的设计中,由于一次客户端操作经常是由多次原子型操作(从业务层面看)组成的,因此可以把这些业务流程的控制逻辑放在EJB层中,并负责对客户端传入结果的解释以及对返回给客户端的结果进行包装。因此,EJB层相当于是一个解释器+业务逻辑组织者的角色,它将业务逻辑的实现推迟到了各个业务对象中来实现,同时有利于各个业务对象中业务逻辑的重用。
下一步关注的重点:
1.采用Spring框架对业务逻辑对象组织方式产生的影响
2.使用OR Mapping对业务逻辑对象组织方式产生的影响