学习.NET架构设计系列:OO设计初次见面(2)
于是在开发中就出现了下面这副景象:每当设计发生变更,我就要修改数据库的设计,用代码生成工具重新生成Value Object,然后重新修改Session Bean里面的业务流程,按照新的参数和返回值修改Helper的代码,最后修改页面的调用代码,修改页面样式。
实际情况比我现在说起来复杂的多。比如Value Object的修改,程序规模越来越大以后,我为了避免出现内存的大量占用和效率的下降,不得不把一些数据库查询的逻辑写到了Gateway和Value Object里面,于是在发生变更的时候,我还要手工修改代码生成工具生成的Gateway和Value Object。这样的维护十分麻烦,这使我困惑OO到底有什么好处。我在这个项目中用OO方式解决了很多问题,而这些问题都是由OO本身造成的。
另一个比较大的问题出在Struts上。投资方为系统设计了很灵活的界面,界面上的所有元素都是可以配置出来,包括位置、数据来源、读写属性。并且操作员的权限可以精确到每一个查看、修改的动作,可以控制每一个控件的读写操作。于是他们希望使用Struts。Struts框架的每一个Action恰好对应一个操作,只需要自己定义Action和权限角色的关系,就可以实现行为的权限控制。但是我错误的理解了Struts的用法,我为每一个页面设计了一个Action,而不是为每一个行为设计一个Action,这样根本就无法做到他们想要的权限控制方式。他们很快发现了我的问题,于是发来了一个说明书,向我介绍Struts的正确使用方式。说明书打印出来厚厚的一本,我翻了一天,终于知道了错在什么地方。但是一大半画面已经生米煮成熟饭,再加上我的Session Bean里面的流程又是按画面来封装的,于是只能改造小部分能改造的画面,权限问题另找办法解决了。
下面就是这个系统的全貌,场面看上去还是蔚为壮观的:
系统经历过数次较大的修改,这个框架不但没有减轻变更的压力,反而使得变更困难加大了。到后来,因为业务流程的变更的越来越复杂,现有流程无法修改,只得用一些十分曲折的方式来实现,运行效率越来越低。由于结构过于复杂,根本没有办法进行性能上的优化。为了平衡效率的延缓,不得不把越来越多的Value Object放在了内存中缓存起来,这又造成了内存占用的急剧增加。到后期调试程序的时候,服务器经常出现“Out of memory”异常,各类对象庞大繁多,系统编译部署一次需要10多分钟。投资方原先是希望我们使用JUnit来进行单元测试,但是这样的流程代码测试起来困难重重,要花费太多的时间和人手,也只得作罢。此外他们设计的很多功能其实都没有实现,并且似乎以后也很难再实现了。设计中预想的很多优秀特点在这样框架中一一消失,大家无奈的接受一个失望的局面。
在我离开公司两年以后,这个系统仍然在持续开发中。新的模块不断的添加,框架上不断添加新的功能点。有一次遇到仍然在公司工作的同事,他们说:“还是原来那个框架,前台加上一个个的JSP,然后后台加上一个个的Value Object,中间的Session Bean封装越来越多的业务流程。”
我的第一个OO系统的设计,表面上使用了OO技术,实际上分析设计还是过程主导的方式。设计的时候过多、过早、过深入的考虑了需要做哪些画面,画面上应该有哪些功能点,功能点的数据流程。再加上一个复杂的OO框架,名目繁多的对象,不仅无法做到快速的开发,灵活的适应需求的变化,反而使系统变得更加复杂,功能修改更加的麻烦了。
在面条式代码的时代,很多人用汇编代码写出了一个个优秀的程序。他们利用一些工具,或者共同遵守一些特别的规约,采用一致的变量命名方式,规范的代码注释,可以使一个庞大的开发团队运行的井井有条。人如果有了先进的思想,工具在这些人的手中就可以发挥出超越时代的能量。而我设计的第一个OO系统,恰好是一个相反的例子。
实际上,面向对象的最独特之处,在于他分析需求的方式。按照这样的方式,不要过分的纠缠于程序的画面、操作的过程,数据的流程,而是要更加深入的探索需求中的一些重要概念。下面,我们就通过一个实例看一看,怎样去抓住需求中的这些重要概念,并且运用OO方法把他融合到程序设计中。也看看OO技术是如何帮助开发人员控制程序的复杂度,让大家工作的更加简单、高效。