DomainModel之持久化

来源:互联网 发布:js调用按钮的点击事件 编辑:程序博客网 时间:2024/04/30 12:49
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;
        }
}

 
原创粉丝点击