经历了错误,才懂得正确的来由。学习就是一个不断经历错误、不断改正、不断得出认知的过程。
---题记
每一位优秀程序员都知道编写一个软件,前期的软件需求分析、软件设计与建模要比编写代码的时间长很多,原因何在?
先来看一个这样古老的故事:
话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:"喝酒唱歌,人生真爽..."。众文武齐呼:"丞相好诗!"于是一臣子速命印刷工匠刻版印刷,以便流传天下。
样张出来给曹操一看,曹操感觉不妥,说道:"喝与唱,此话过俗,应改为'对酒当歌'较好!",于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。
样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:"人生真爽太过直接,应改问语才够意境,因此应该为'对酒当歌,人生几何?......'",当臣转告工匠之时,工匠晕倒......
可惜三国时期活字印刷还未发明,所以类似事情时有发生。如果有了活字印刷,则只需更改四个字即可,其他的工作也都未白做,实在妙哉。
这个故事恰恰体现了面向对象编程中的几大特性:一.要改,只需要更改要改之字,此为可维护;二.这些字并非用完这次就无用,完全可以在后来的印刷中重复使用,此乃可复用;三.此诗若要加字,只需另刻字加入即可,这是可扩展;四.字的排列其实可能是竖排可能是横排,此时只需将活字移动就可做到满足排列需求,此是灵活性好。
其实客观的说,曹操这样的客户的要求也并不过分,不就是改几个字嘛,但面对已完成的程序代码,却是需要几乎重头来过的尴尬,这实在是痛苦不堪。其实,原因出在我们原先写的程序,不容易维护,灵活性差,不容易扩展,更谈不上复用,因此面对需求变化,加班加点,对程序动大手术的那种无奈成了非常正常的事了。
之后,我们了解了面向对象的分析设计编程思想,开始考虑通过封装、继承、多态把程序的耦合度降低,传统印刷术的问题就在于所有的字都刻在同一版面上造成耦合度太高所致,开始用分层的结构使程序更加的灵活,容易修改,并且易于复用。
了解了面向对象的好处,编写软件当然要向可维护、可扩展、灵活性好等方向发展,这不我的小软件"机房收费系统"中就使用三层架构思想建模,加上了一些设计模式。
这时我们需要了解一下分层的目的:分层是为了解耦,更换掉一层不至于使系统重新做。
1.初始经典的三层架构图:
面向对象语言几个特征:封装、继承、多态。这里的三层架构图是逻辑上的分层,把一个系统分成三层,每一层具有的职责不同,也就是将每层具有的功能封装起来。在DAL层连接不同的数据库使用多态的思想。
2.迷糊状态:我初次改造的"机房收费系统"三层架构图
三层架构包图对应的程序集中的项目
这时,我的理解仅仅停留在:具有UI、BLL、DAL层的系统就是使用了三层架构思想;当然三层架构系统中还可以加设计模式、SqlHelper等层,这时使系统具有多层;也稍微了解每层应实现什么功能。
这里我犯了几点错误,从图中可以看出
1) 命名不规范,当时我以为此系统是"机房收费系统",所以就在UI、BLL、DAL等前面加上了字母"JF",对于实体因为我看了一个视频中某老师使用的是Model,我也跟着写成了Model,没去问为什么。
2) 根本不理解三层之间真正的调用关系。没分清哪一层调用哪一层的方法,没明白谁向谁传参数。
3)理论上明白分层的目的,实际操作时却丢了分层的目的。我把设计模式"工厂方法"放到了D层,本来要使B层和D层分开的,我的做法恰恰不让他们分开;虽然程序可以实现,但是我违背了解耦的原则。
3.豁然开朗:经过师哥师姐指正,重新建模
通过师哥师姐帮我分析,前后对比,我明白了分层的真正目的,也明白了自己上图的做法并没有解耦。
犯错了,领悟了,才了解为什么这么做是正确的…
经过"机房收费系统"这个建模过程,我得到了几点系统建模经验,写出来与大家分享……
经验1.真正理解三层的意义,包之间的引用关系
所谓三层开发,就是关于表现层、业务逻辑层和数据访问层的开发。这其实只是大方向的分层,每个层中都有可能再分为多个层次和结构。三层架构中,上层包向下层包传递参数,上层包调用下层包的方法,下层包向上层包传回返回值。
经验2.既然用设计模式,就要明白设计模式的真正意义
这里我用到了工厂方法模式,工厂方法模式到底是干嘛的?工厂是用来创建对象的,实际上这里的工厂是为了生产DAL。使用工厂方法是为了使BLL层与DAL层解耦,另一个作用是为了使数据库更换方便。
注意:这个三层架构中使用了工厂+反射,若只使用工厂而不使用反射,又怎么建模呢?
经验3.架构图要与程序集代码完全对应
软件设计完,编写代码过程要完全按照图来进行,图和文档是我们编写代码的依据。这里所说的对应不仅仅指包图名称与程序集中项目名称对应,而且要使包中的引用关系与程序集中的引用相对应。
注意:程序集中的引用项与包图之间的引用关系是一个意思。
经验4.程序集中的项目引用项,不能添加多的引用,也不可少引用某层
看下图
这个图添加的引用是正确的,有的人在调试程序时出错,就在引用项中加入了"DAL"。看下面的错误图,比较与上图的区别:
在UI层引用"DAL"就错了,因为编写好的程序打包后DAL不是仅仅打包成一个.DLL文件,而是将DAL.DLL文件打包到UI中了,这样做,更换DAL时,系统就会报错。为了解决这一问题,需要使用深层路径,只是将DAL的路径打包到UI中,也就是使引用中不含有DAL 而 debug项中含有DAL相关项,这样打包完依然是解耦状态,这时更换DAL,只要路径对了,就不会报错了。
还有一点,有的人将SqlHelper数据库工具类写到了DAL层,这样做也是破坏了解耦原则。
经验5.命名要规范
编写的代码 or 画的UML图不仅仅是给自己看的,更多的是用来交流。为了保证代码的一致性,便于交流和维护,编写代码要遵照一定的规范。
经验6.注释要清晰、正确
有没有这种感觉,写过去的程序放几个月再回头看,不知道这段代码写的是什么了?原因在于你没有写好注释。注释不仅仅是写给自己,也是让自己的队友来看的。这些都是良好的编程习惯,慢慢养成。
通过这次"机房收费系统"建模,对软件的编写过程有了更清晰的理解。上面介绍了我的建模过程及我从中获得的经验,既是我学习过程的总结也希望对看到此博客的人有益!