DomainModel之持久化

Aspect在DomainModel持久化的应用,是我所知,AOP较为成功的例子之一。就目前AOP应用来说,

非对称模式要比对称模式,更容易找到应用领域。我想这主要是因为非对称模式,更接近于OO传统思路。对于非对称模式来说,基本上,扩展者和被扩展者是通过切点(扩展点)联系在一起,被扩展者相对完整。扩展者也只需要关注切点展现的对象和对象特征。

而对于对称模式,是通过对象来封装?还是通过Aspect来封装,如何划分和封装?确实缺乏有效指导。我想,这是阻碍AOP推广的重要原因。或许,需要找到一种“化学反应中催化剂”技术,AOP才能充分发挥其特有威力。

说到持久化,意味着两件事,1.把DomainObject存储到存储器上(通常是数据库);2.把DomainObject从存储器中重新构建出来。

下面来看看,AOP是如何巧妙处理DomainObject持久化的第一件事。把DomainObject的存储看作是DomainObject的一个方面,无疑是解决问题的关键。按照这种思路,DomainObject只需要关心业务逻辑,不必关心自己是如何被存储到数据库中,Aspect会来打理这一切。

如何建立该Aspect呢。首先,我们考察对DomainObject存储都涉及到哪些操作?这个问题很简单,共有增、删、改三种。各位闭上眼睛也能想清楚。接下来,看看这三者是在什么时候发生的。“增加”--意味着在业务上创建,意味着一个“生命”的开始。这和构造函数很类似,区别仅仅在于构造函数只意味着在内存中创建对象。所以我们可以考虑把切点写成,截获那些确实表示业务上创建DomainObject的构造函数返回。对于“删除”来说,确实找不到好的对应概念,所以,我们不得不添加一个什么也不做的destroy方法,来表示在业务上,该DomainObject我们不再需要,让它回归伟大的“虚无”。“更改”呢?“更改”意味着,DomainObject属性发生变化。尽管我们可以考虑监视字段变化,但通过set和add、remove等方法,似乎更加容易理解,因为对这些方法的调用就意味着DomainObject被改变了。这样我们就完成了所有操作的切点分析。借助于MartinFowler的UnitOfWork模式,完成DomainObject的Lifecycle Aspect就不是什么难事。

接下来,我们要考察,DomainObject持久化的第二件事。把DomainObject从存储器中重新构建出来。虽然DomainObject不知道持久化的具体实现,但是知道查询接口还是允许的。但仅仅是接口,没法直接使用。我们还需要把它的实现注入进来。在注入前,我们需要想好,这些接口的“居所”。如果一个DomainObject--A需要通过查找接口找到另外一个DomainObject--B,似乎我们可以把这个接口作为A的成员来完成这样的需求。考虑到,查找接口的实现有无状态的特征。进而,我们可以考虑把它作为A的静态成员,来为所有A对象实例服务。这确实比对象级别注入效率高很多。不过,我们还是看到了不少重复代码,因为DomainObject--C也需要查找到B,按照前面的设计,我们不得不在C中也静态注入B查找接口。我们需要寻找一个,单点维护的地方来锚定查找接口。确实有这样一个地方,那就是在B类上静态注入B的查询接口。这样对于任何想获取B类查找接口的请求,都可以通过B.getBFinder得到。这里其实还有一个小小的问题,“对于通过比B类高的对象D,来查找B,由于,B类不该引用比自己高的类D,但是B的查找接口绑定在B类上,就导致了B类间接引用了D”,对这个问题的思考结果,我的回答是:“通过AOP的Inter-type来完善对于B查找接口的声明。”曾经还想过其他的一些方法,最终还是认为这是最直接和优雅的一种。

java代码: 

public aspect Lifecycle
{
        protected pointcut create ( ):
                !within (com.. data..* )&&
                call (IDomainObject+. new (.. ) );

        protected pointcut modify (IDomainObject domainObject ):
                target (domainObject+ ) &&
                (call ( void IDomainObject+. set* (.. ) ) ||
                        call ( void IDomainObject+. add* (.. ) ) ||
                        call ( void IDomainObject+. remove* (.. ) ) ) &&
                !call ( static void IDomainObject+. set*Finder (.. ) ) &&
                !withincode (IDomainObject+. new (.. ) ) &&
                !within (com.. data..* );

        protected pointcut destroy (IDomainObject domainObject ):
                target (domainObject+ )&&
                call ( void IDomainObject. destroy ( ) );
       
        after ( ) returning (IDomainObject domainObject ): create ( )
        {
                UnitOfWork. getCurrent ( ). registerCreated (domainObject );
        }

        after (IDomainObject domainObject ): modify (domainObject )
        {
                UnitOfWork. getCurrent ( ). registerDirty (domainObject );
        }
       
        after (IDomainObject domainObject ): destroy (domainObject )
        {
                UnitOfWork. getCurrent ( ). registerDestroyed (domainObject );
                       
        }
}


典型的Finder锚定
java代码: 

public class Customer {
        private static ICustomerFinder customerFinder;

        public static ICustomerFinder getCustomerFinder ( ) {
                return customerFinder;
        }

        public static void setCustomerFinder (ICustomerFinder customerFinder ) {
                Customer. customerFinder = customerFinder;
        }
}


确保Finder都正确IOC的断言

java代码: 

public aspect FinderVerification {
       
        private pointcut setXXXFinder ( ) :
                execution ( public static void IDomainObject+. set*Finder (.. ) );

        private pointcut getXXXFinder ( ) :
                execution ( public static * IDomainObject+. get*Finder ( ) );

        before ( ) : setXXXFinder ( ) {
                String methodSignature = thisJoinPoint. getSignature ( ). toShortString ( );
                assert thisJoinPoint. getArgs ( ) [ 0 ] != null : methodSignature + " 参数为 null";
        }
       
        Object around ( ) : getXXXFinder ( ) {
               
                Object finder = proceed ( );
               
                String methodSignature = thisJoinPoint. getSignature ( ). toShortString ( );
               
                assert finder != null : methodSignature + " 返回 null ";
               
                return finder;
        }
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值