实体类是个什么东西!答金色海洋同学的疑问
其实不想再啰嗦这个问题,但是要回答的东西很多,所以还是另起贴回复了。之前从很多方面来解释了分层,但是对于实体类这个家伙由于是一个一根棒子捅到底的异类,所以引起金同学的疑问,由于涉及到我的另一篇post,所以不得不作出几点说明。
其一,实体类是什么?
这里我做出一个符合大多数系统的定义:实体类就是只有属性且属性与数据库表的列定义一一对应,用途为在各个层次间传递数据的载体。也即是DTO(Data transfor object,大致这么拼写的)数据传输对象,java里叫pojo。那么我认为这个类的定义就是一个数据结构。
那么我们回过头来说数据结构。程序就是 数据结构+算法,这句话算是经典了,那么面向对象的程序里,类就是数据结构+算法的一个集合体,唯一的不同是面向对象提成封装,数据结构为私有,这样子通过方法作为契约来降低类之间的耦合度。但是,这不能从根本上解决问题。程序的数据不是内部 凭空而来,无论是输入还是输出都需要和外部由一个接口,那么这个时候这个接口就是一个耦合点。之前谈耦合的时候估计金同学没认真看,在接口的契约中,应该考虑采用标记耦合
------------无耻的自我引用----------------
标记耦合 :一组模块通过参数表传递记录信息,就是标记耦合。这个记录是某一数据结构的子结构,而不是简单变量。
------------------------------------------
其实实体类就是这个:某一数据结构的子结构。
我们可以认为,数据库的结构也是一种数据结构(从数据结构的广义定义来说,确实是数据结构,数据存储的结构),那么实体类作为数据库表结构在程序中的映射来说也就是一种数据结构了。那么
CreateUser(UserEntity user)
这样子的“接口定义”(注意引号,此接口非彼接口)就是所谓的标记耦合了。
再对比一下公共耦合的定义:
------------无耻的自我引用----------------
公共耦合:若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。
------------------------------------------
数据库作为全局的数据结构,自然也够得上公共耦合了,如果要真这么定义那么也没办法解决,这是个无解的问题,要用数据库就比如和这个公共的数据结构耦合。
而且,必须注意的一点是,耦合是模块之间的消息传递、数据传递的途径,耦合是中性的,不可避免的
所以在这点上努力是纯粹的在做无用功。也即是即使不用实体类,那么数据库的结构变了,也即是数据结构变了,那么修改代码是必然的,不可改变的结构。正如同操作数组做冒泡排序的算法如果把数组换成了hashtable还能正常工作?
DataSet,不管强类型的还是弱类型的,DataReader都是要和数据库耦合的,所以这两个和实体类没什么区别。
难道我们什么都不做? 答案是否定的
就我现在的观点来说,解决之道就是动态。ORM用实体的定义作为契约,动态化了对数据的访问,所以如果数据库发生了变更我们只需要修改实体类和定义,这就大大的减小了对程序的修改。spring动态化了对业务模块的依赖,我们可以很容易的替换业务模块。那么如果数据库发生了变更,在修改实体类和定义的基础上我们只需要数据库修改的表所涉及的业务模块用新的替换掉就ok了。而界面上,动态的表单和数据控件也能够极大的减小修改的幅度。
这里有一点是需要对金同学说明的:你的控件就算是用事件把一部分业务逻辑的工作剥离出来,但是业务逻辑是和数据耦合的,那么你用什么来让业务逻辑知道你的数据结构?数组?DataReader?DataSet?
表单所以依赖的数据结构变化了,配置变不变?所谓配置也就是程序的一个延续,我认为配置其实就是一种外置的DSL(见 why xml sucks)
修改配置文件和修改程序,很多时候由一个误解认为修改xml文件比修改程序好,殊不知xml文件的修改没有经过编译时的检测,而程序是通过了编译时检测的,修改xml的出错几率比修改程序高100倍(这点我好像在 why xml sucks 里头漏掉了)。
说回来,数据表的结构变化了,其实还是会涉及到对界面的修改,只不过你的控件把这个修 改从页面文件剥离出来,改成了修改配置文件(或者配置数据)。如果没有工具来完成配置的工作,出错的几率比修改页面高得多,且debug也复杂得多。
还有一点要对回复金同学疑问的一些同学说的:好多同学对spring的理解委实有很大的偏差。spring是一个ioc容器+aop容器+抽象服务的集合体,当然我们用的最多的是前两者。很多同学吧ioc和aop弄混了。ioc是依赖注入的概念,其实也就是对虚拟工厂模式和代理模式的实现,而aop是方法切片,也就是在调用方法的前面和后面动态的植入另外的要执行的代码(其实也就是方法)。