Month: August 2008

实现“可移植性”(portability)的关键

    啥叫“可移植性”?可移植性就是当消费者对供应商的服务不太满意时,可以换用另一个供应商,并且不需要调整自己接受服务的方式。典型的例子有:JAVA程序 V.S 操作系统,应用程序 V.S. 数据库    观察这些例子,可以发现实现可移植性的关键是:存在着一个中间层适配器,将供应商的接口适配为消费者想要的服务。供应商变了,适配器也要换。把java程序从windows迁移到linux,就需要换用linux下的jvm;把数据库从sql server换成oracle,就需把jdbc驱动换成oracle的驱动;而对应用程序开发人员来说,常常需要考虑的是,当服务组件从EJB换成Web Services时,应用层的代码要怎么改? 解决办法和上面一样,在一开始设计的时候就要在应用层和服务层之间设计一个适配器接口以适配服务组件的接口,当服务组件更换时,重新写一个类实现这个适配器接口就可以了,应用层代码本身不需要改动。    实现可移植性还有一个约束:消费者所需的服务必须是独立于任何供应商特性的。如果在应用层的数据库查询代码里用了“select top 10 ….from …”,那么这个系统就只能用在sql server上了

较弱的代码可重用性 => 较强的代码重复性

    一份代码的可重用性(reusability)较弱,这就表明这份代码的内聚性差,即同时揉合了服务提供者的代码和使用服务者的代码,由于服务提供者的代码没有独立成一个模块,其他的调用者只得把这些代码拷贝一份,跟调用者的代码耦合在一起,结果,代码变得重复了(Dupliacted Code)。    比如,直接在JSP里用SQL访问数据(数据的提供者)并展现数据(数据的使用者),这样的代码几乎没有任何可重用性;同时,别的JSP页面想展现类似的数据时,也只能拷一份相同的SQL再拷一份相同的JDBC语句。    较强的代码重复性,意味着较多的重复劳动;更可怕的是,当服务提供者的实现发生变更时,由于它的代码被复制了多份,结果导致每一处的拷贝都要做一下修改,非常浪费时间。而这,就叫做 可维护性 (maintainability)

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

    区别就是当“实现”发生根本性的变更时(比如数据库平台更换导致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.以后如果增加了新的交互功能,要尽力保证新的报文会使所有报文集在解析时不会出现二义性(如维持上下文无关文法),比起可随意取名的、可随意重载、可随意覆盖的 对象方法 要麻烦多了