框架设计之旅(1)--数据的分层
所谓的数据分层就是我们做数据库类的软件开发时,涉及到和数据库打交道的数据分层。为了可以让代码可以重复利用在更多的地方,为降低模块与模块之间的耦合性,我们必须对这个分层有一个宏观的规划,考虑更多的情况。下面,是我的数据分层的设计理念:
我们来先看图,对图有个充分的认识后,才对下面描述的文字有更好的理解:
一、 数据的分层:目前流行的分层以3层为主:DAL/DAO(数据库访问层)、BusinessManager/BLL(业务逻辑层)、Model/VO/Entity(数据模型/数据实体)。(其实,我都分不清这些业务术语的,我只知道有这3层,我知道我该如何去设计,所以我也懒得去管他那些专业术语了,所以,本文如果在专业术语中有什么不对的,请指点一二。)为何要分这3层是有原因的:
1) Model/VO/Entity(数据模型/数据实体):根据数据库中的表进行数据建模,模型不涉及任何业务逻辑,因为该模型只是数据库中的一个表/视图的映射。如果你在这里编写了涉及到业务逻辑在这层,那么,如果别的公司要求做同样的项目时,这公司的逻辑与你之前的设计有出入的话,你这层就得改了。特别是在做产品时,就更要注意,千万不要在该层写业务逻辑的代码。如果要写,可以,派生出该类的子类。
2) BusinessManager/BLL(业务逻辑层):负责把业务中对数据实体的影响反映到数据源中,如:增删改。同时也把数据源中的情况反映给外界,如:查询。该层其实是作为一个中介层,介乎于数据实体与数据库之间,其存在的意义在于数据访问层有可能变化,如使用myBatis.NET、NHibernate、Linq等ORM工具访问数据库,该层的意义就在于其数据访问层改变的情况下不需要改变其代码而存在的,至于其为何叫业务逻辑层,我在这里有所保留,我只认为,该层的业务逻辑在于其对数据库的增删改查业务的处理,因此,我也奉劝大家,不要在该层写不同项目中不同的业务逻辑代码。如果要写,可以,派生出该类的子类。
3) DAL/DAO(数据库访问层):负责从BLL层获取数据更新到数据库,以及把数据从数据库中提取出来提供给BLL层使用,是直接操作数据库的一层,该层一般情况下是封装myBatis.NET、NHibernate、Linq等工具。
二、 具体实现数据层:刚才介绍的3层中,其中我提及到,不要把业务代码直接放在BLL层以及Entity层,而采用派生的子类,是有原因的:
1) 很多时候,我们都会使用代码生成器把3层的代码直接生成出来,而不需要手工去敲(如果有100多个表,这样敲,是我肯定不会干这种事了),这样,如果你把生成出来的代码修改了,当你的表要加字段,改字段名等变更时,你得重新去生成一次(你不重新生成么?那你自己去敲了,我是不会敲的。你不懂目前架构,不知道要在哪敲代码?那我也不会帮你敲),这种种情况,我都不提倡手工去改这些代码,因此,我是肯定不会把这些有业务逻辑的代码写在代码生成器自动生成的模块中,因此,我,是必须把业务逻辑的代码写在派生的子类中,这样,就不会在重新生成代码时把原来手工修改的代码冲掉。
2) 这点是非必要,但,这点是我提倡的,如何划分项目:把代码生成器自动生成的类划分到一个项目中,该项目包括:Model_Auto、BLL_Auto、DAO_Auto、Service_Auto、Config_Auto放在一个project_Auto的项目中,把Model、BLL、DAO、Service、Config放在一个project的项目中,这个项目的所有类都继承*_Auto类的。在实际应用中,project项目肯定经常需要修改,在字段不变的情况下,我们基本上不需要重新编译project_auto。现在,我们模拟这个现成的项目应用在另外一个环境(公司),导致了某些表的业务逻辑需要改变,我们可以有以下的解决方案:
i. 像做project项目一样,把project项目拷贝出来,另存为project_B项目,根据实际环境的需要,想怎么改就怎么改。
1. 优点:对别的项目没有影响,各自有各自的业务逻辑,独立维护。
2. 缺点:当出现BUG时,而这个BUG涉及到project和project_B的话,就增加了代码的维护量,当如果管理不善,对project和project_B不熟悉的,和有可能只更新了一个而另外一个没有更新。
ii. 把与project不一样的逻辑独立出project_B,project_B中的类可以根据实际情况,从project_Auto中派生,也可以从project中派生出来,业务逻辑一样的继续使用project的类,根据需求使用project_B中的派生类。
1. 优点:尽可能把不同的应用环境中的特殊情况独立出来,发现共同的BUG,只需要修改project中的代码,修改后,不同的应用环境直接替换对应的dll文件即可。
2. 缺点:在不使用接口方式编程的,导致模块与模块之间的耦合性太强的时候,可能需要修改使用到这个类的地方的代码,因为使用的类已经变化了,不改是不行的。如果使用了接口方式编程,可以只需要在创建时,修改创建的类即可。如果使用spring.net来实现对象工厂时,只需要修改相关配置文件就可以达到一种热插拔方式来编程,从而摆脱这种缺点的出现。这种方案也是我所推荐的解决方案。
iii. 修改project中有变化的类中增加参数,用参数来区分开不同的应用环境使用不同的方法。
1. 优点:方便修改,只需要根据实际情况进行修改。
2. 缺点:代码维护起来存在一定的不确定性以及风险,而且会导致编码时多一个心眼要去关注参数的影响,以及要考虑到没有设置该参数时的情况如何处理。当应用到的地方越来越多时,参数的变化而导致的工作量会成倍地增加,类也会变得越来越大,函数或者过程同样会根据不同的参数的增加而变得更长,维护起来十分不方便。
iv. 小结:选择哪一种方案就见仁见智,根据实际情况去选择,很多时候,project不一定有源码,因此,第二种选择是相对独立的解决方案,但也有一个要求,就是project中大部分的方法允许重载才行,否则,还得去修改project的代码才能让其派生出来的project_B中的类进行重载相关方法。其实,对于系统的维护,基础模块一般情况下需要对其项目有很深入的了解,十分熟悉其内部运作,否则,很有可能修改的代码,会引起不同项目产生不同的负面影响,从而产生出更多的BUG。因此,基础模块(project_Auto/project)必须充分规划好,管理好,不要随便开放给开发人员随意修改,要充分考虑其扩展性与兼容性。
原创作品出自努力偷懒,转载请说明文章出处:http://www.cnblogs.com/kfarvid/