Chen Jian

用 接口 + 实现类 跟直接用 一个实现类作为接口 对开发人员来说有什么区别?

    区别就是当“实现”发生根本性的变更时(比如数据库平台更换导致SQL语句变更),如果直接使用实现类作为接口,则需要直接“修改”实现类的代码;而如果使用 接口 + 实现类 模式, 则只需“新建”一个实现类,并切换接口对应的实现(一般情况下这只需要修改配置文件)。    一般情况下,“修改”和“新建”并没什么区别,直接调用实现类的方法,并不需要知道方法内部的实现,其透明性和 接口 + 实现类 的模式是一样的;但如果考虑到一个软件机构的代码一致性的话,区别就很大了。对一个成熟的软件机构来说,同名(包括包名和类名)类文件的功能应该基本相同,虽然这些代码文件属于不同的系统。 如果BookDAO类在系统A中使用SQL SERVER,而在系统B中对应Oracle,这是很不合适的;而如果采用 接口 + 实现类 的模式, 可以将接口名称为BookDAO,而在两个系统中的实现类分别叫做BookDAOSqlServer和BookDAOOracle,这样就比较体面了

Aggregation和Composition的区别

Aggregation […] is the typical whole/part relationship. This is exactly the same as an association with the exception that instances cannot have cyclic aggregation relationships (i.e. a part cannot contain its whole). Composition […] is exactly like Aggregation except that the lifetime of the ‘part’ is controlled by the ‘whole’. This control may be direct …

Aggregation和Composition的区别 Read More »

程序和数据要尽量分开,不要让 数据 承载 业务功能

       让 数据 承载 业务功能,比如用SQL来配置业务逻辑,可以减少硬编码,新增功能时不须重新开发,但是,一旦生产环境中的数据库被破坏,不但破坏了业务数据,也破坏了业务功能本身。这些被破坏了的业务功能,恢复起来是很困难的,除非每配一次业务逻辑,就记录一下对应的SQL语句.     如果将业务功能都写在程序里(比如代码里),那就不存在这个问题了

在新增记录时清除过早的历史记录 —- 免去了维护负担,保持了数据完整性

     系统里为了防止数据库中记录太多,一般都要将过早的历史记录清除掉。一种策略是写一个SQL脚本,然后定期执行,这会带来一定的维护量。而且还有一个问题,如果一条业务记录分散在多个表中,删除记录时要非常注意这些表的关系,尤其是外键关联的级联特征,这可能会导致SQL脚本比较复杂。        而我常用的策略是,系统在新增某类记录时,自动删除过早的记录。这样就没有了额外的维护负担,而且,由高级语言写成的程序,在删除跨表记录时可能更便捷,更能保证数据的完整性。

O/R Mapping中的n+1 select 问题

假设对象A关联对象B,对应地, 表a 关联 表b(表b 外键参考 表a) 现在我们要把所有A和其对应的B 从数据库中翻出来 如果不用O/R Mapping,直接用SQL,则可以写一条连接两表的SELECT语句搞定         select * from a join b on b.aId = a. aId 如果用O/R Mapping,实际生成的SQL可能是        select * from a   (假设取出的a的ID分别是 1,2…n)        select * from b where b.aId =  1        select * from b where b.aId =  2        ……        select …

O/R Mapping中的n+1 select 问题 Read More »

EJB的优点和缺点

优点和缺点是从《without EJB》第一章概括出来的,希望我没有曲解作者的意思:    优点:       1.仍是最好的的业务对象分布式架构。无状态session bean还是不错的。       2.消息Bean也不错。尤其是对金融系统来说    缺点:EJB乃至整个J2EE规范的缺点,可以用一句话来概括:花了80%的时间去处理那些20%的问题,得不偿失。典型的例子就是开发人员凭空想出一些不切实际的需求来捆住自己:       1.系统除了支持web客户端,还要支持swing         2.系统所用的数据库产品和应用服务器可能会改变       3.系统可能使用两个数据库       4.系统可能不用关系数据库作持久化,有可能用XML作数据源 我个人对Rod Johnson的以下看法持保留意见:    1.他说,在远程调用方面,web services是比EJB更好的选择。按我的经验,web services的配置复杂性非常吓人。    2.他还说,分布式对象方案 破还了OO原则,因为出于性能考虑,需要为远程方法定义比本地接口要粗糙的远程接口。这破坏了透明性。但我觉得,这种透明性本来就没要去追求。       a.进行分布式交互的两个对象,未必就应该是业务对象,完全可以是一些控制指令。这些控制信息专用于远程交互,不会和本地业务对象实现同一个接口       b.分布式对象之间交互时,本来就不会涉及多大的数据量,否则就会用文件来传递数据了       c.再考虑不使用分布式对象的机会成本。不用这种东西,就要用socket、web service或者其他中间件。后果是:          I.配置文件多了          II.与配置文件的配套的设计文档、安装文档也多了          III.最头疼的是,要专门一个协议。比如定义一个报文,这个报文的这个字段代表什么,字段是什么类型,长度有多少等等。              A.这个工作量不小              B.以后如果增加了新的交互功能,要尽力保证新的报文会使所有报文集在解析时不会出现二义性(如维持上下文无关文法),比起可随意取名的、可随意重载、可随意覆盖的 对象方法 要麻烦多了

Hibernate: 设A引用了B,则删A后可能要evict(A.getB())

Hibernate: 设A引用了B,如果要先取A删A再取B删B,则删A后可能要evict(A.getB()),才能顺利删除B 否则,就会报错:a different object with the same identifier value was already associated with the session 原理是这样的:        第一步将A从数据库中取出时,它引用的B也从数据库中取出,两者同时成为持久化对象。A删除后,B是处于Session中的持久化对象       第二步中又显式地将B从数据库中取出,加上第一步中取出的B,Session里就有两个B了。这时侯如果删B,就会报上面所说的那种错误。        因此,应该在删除A后立即将它引用了的B从Session中清除掉。即:        A   =  Session.load(A);        Session.delete(A);        Session.evict(A.getB());        Session.delete(B); =============================================== 注意:evict()并不会级联,除非设置了相应的cascade 也就是说,如果B引用了C, evict(B)时不会自动evict(C) 看官方文档: This operation cascades to associated instances if the association is mapped with cascade="all" or cascade="all-delete-orphan".