细节:构造对象与属性存取

一、关于构造对象
在Hibernate中,要持久化一个pojo,必须执行类似Session.save(myobj)这样的方法,通知事务上下文加入这个持久化请求。在执行这么方法前,任何操作对于持久层都是没有影响的。在持久层收到持久化请求后执行持久的时候,通过解析过的配置文件将这个pojo持久化。所有的一切都是在一个透明的过程中完成的。Java自始至终强调一个纯净的环境,不赞同业务层的类被污染,所以Hibernate无法关心业务类的属性的具体实现。如果一个新new的业务类实例需要引用到某个已经持久化过的实例,你必须立即请求Session去Load一个实例出来,尽管可能这个实例其实已经Load到事务上下文中了。Hibernate可以不管这些,他完全有理由将任何保持类实例的事情交给另外一个层去完成。
在.net下没有那么幸运,持久层还必须承担起对已加载实例的管理。例如,每个产品的实例已经加载到了事务空间,这样才能给UI层提供一个列表让用户选择哪一个产品。当操作者选中某个产品后立即将该产品加入到新建订单的“所选产品”属性的引用中。在Hibernate中列出这个产品的清单是一个Activity完成的,而新建一个订单是另外一个Activity完成的。
这里便冒出来一个问题,有两种策略来处理新建的实例。一是象Hibernate那样,任意new一个object,然后通过save方法将实例提交给Session。另外一个是直接要求Session代劳建立一个object实例,这样从一开始这个object实例就是由Session来管理了,然后任何时候都不需要执行任何方法来提交。第一种方式非常自然,但是我认为第二种方式更有效。
什么时候需要在业务层的代码中构造实例?只有一种情况,那就是需要新建一个从未持久化过的实例。需要update或者delete的对象一定是从持久层load出来的,从实例构造时起就具备事务环境的特性。我一向比较崇尚“对称法则”,所以,新建一个对象和删除一个实例设计一组完全对称的方法。而修改就比较简单了:在属性第一次被修改的时候就立即丢进事务上下文中,只等事务提交时就直接持久化。

二、关于属性存取
近日一直在研究实体结构问题,感觉非常令人困绕。以往我都必须要求实体结构必须自一个BizObject基类派生,但是这个BizObject只负责完成对属性的管理。重载的实体类型必须使用基类提供的属性存取方法GetValue和SetValue:

public Product Product
{
    
get
    
{
        
return (Product) GetValue(3);
    }

    
set
    
{
        SetValue(
3, value);
    }

}

代码中的“3”是一个属性访问键,由配置器来管理。访问键不一定要求连续,但必须唯一,并且getter/setter使用同一个访问键。
这种方式自然是剥夺了用户自己实现属性存取方式的自由。但是框架却获得了非常有利的条件。对于框架来说,你的实体有1000个属性或者1个属性,都是通过同一种方式来处理。对Null值的处理自然也完全满足了数据层的需要。
将getter/setter交给框架来处理还有一个逻辑上的合理性,因为Session在Load实例的时候访问属性就不是那么自然。我不是特别明白Hibernate如何在load的时候返回一堆proxy给请求者。设想一下,业务层已经为实体属性准备了一个field,Session是无法不通过属性的getter/setter就能够将属性与field一一对应。那就是说,所有load出来的proxy必然是proxy自己的field提供的,Hibernate通过override实体的getter方法将自己从数据层读出的数据呈现给实体的instance的属性。OOP不介意加多几个方法,但是非常介意加多几个field的。

呵呵。以往的Kanas.net是给每个实例分配了一个Hashtable,自然是以访问键为键值,属性值为值来实现的。前些日子做了一个性能测试,当加载100万行数据的时候占用了超过400M空间(其实每个实例应该只占40个字节左右),而且速度不堪忍受。而使用Field-Property的存取方式只占用了103M空间,而且速度非常快。1.3版的Kanas.net放弃了这个Hashtable的方案,采用更为合理的DataCell(数据囊)方案。不仅保持了原来的对Null值的控制,而且不需要象Hashtable那样频繁地Boxing/Unboxing。测试的结果是:同样的100万行数据,占用了123M空间,速度也与Field-Property相差无几。数据囊不是一个彻底的proxy,更象一个wrapper,但是却比proxy更协调、更节省,但是就必须有一些更苛刻的限制:彻底剥夺用户自己实现属性存取的自由。

剥夺用户自己实现属性存取的自由,还有一个额外的理由。在Kanas.net 1.3版中,要实现一些只读属性(例如汇总字段、计算字段),如果由用户自己去实现属性存取的话,框架没有额外的方法将从数据库中所获得的值填充到那些只读的属性中。呵呵,那些属性是不能修改的,你可以不用写这个属性的setter,这样如果你的代码中有修改这个属性的语句,首先编译器就不干(又一次利用了语言和IDE的特性)。

总结起来是这样的:一、Kanas.net 1.3剥夺了使用者对实体类型属性存取方式的自由,必须由框架提供的数据囊工厂来创建和访问。这样可能有些专制,但是为了得到更好的控制不得不这样。二、用户可以new一个对象,然后尽早调用Attach方式将这个对象提交给事务上下文,当然,直接由事务上下文来代劳创建这个实例可以获得更多额外的好处。三、Kanas.net为用户保留了实体类自由地从某个基类继承的自由,但是仍然可以从BizObject继承,这样至少你不用写创建数据囊的代码了。

posted @ 2005-08-04 02:15  双鱼座  阅读(298)  评论(0编辑  收藏  举报