用于Java类的特定于版本的实现的模式

时间:2010-05-20 17:19:21

标签: java hibernate design-patterns spring

所以这是我的难题。我正在编写一个需要处理旧版本应用程序的工具。我有应用程序的代码,但不能改变任何类。为了从我们的数据库中提取信息,我有一个由Hibernate填充的各种DTO。它使用我们的应用程序版本1.0的数据对象,巧妙地命名为DataObject。以下是DTO课程。

public class MyDTO {  
    private MyWrapperClass wrapper;  

    public MyDTO(DataObject data) {
        wrapper = new MyWrapperClass(data);
    }
}

通过Hibernate查询实例化DTO,如下所示:

select new com.foo.bar.MyDTO(t1.data) from mytable t1

现在,在数据对象之上需要一点逻辑,所以我为它创建了一个包装类。请注意,DTO存储包装类的实例,而不是原始数据对象。

public class MyWrapperClass {

    private DataObject data;

    public MyWrapperClass(DataObject data) {
        this.data = data;
    }

    public String doSomethingImportant() { ... version-specific logic ... }
}

这很有效,直到我需要处理我们的应用程序的2.0版本。现在两个版本中的DataObject非常相似,但不一样。这导致了MyWrapperClass的不同子类,它们实现了自己特定于版本的doSomethingImportant()。仍然没事。但myDTO如何实例化适当的特定版本的MyWrapperClass? Hibernate反过来实例化MyDTO,所以我不能在Spring中@Autowire依赖它。

我很乐意将MyDTO(以及我的许多其他DTO)重用于该工具的两个版本,而无需复制该类。不要重复自己,等等。我敢肯定,我错过了一个非常简单的模式,这对我们有所帮助。有什么建议吗?

2 个答案:

答案 0 :(得分:1)

您可以使用Hibernate Interceptor实现instantiate(String entityName, EntityMode entityMode, Serializable id)

在该方法中,您可以将MyWrapperClass传递给数据对象。根据应用程序的版本,包装器将有所不同。拦截器可以设置在会话级别或会话工厂级别。

答案 1 :(得分:0)

我和我的同事尝试了很多选择。我们决定使用Hibernate的文档记录很差的ResultTransformer接口(实际上,Hibernate,缺少文档是可耻的)。尽管使用Transformer迫使我们在MyDTO构造函数中手动解析Object []数组,但这是一个值得权衡的权衡。

在ResultTransformer中,我们通过Spring注入了特定于版本的WrapperFactory。我们更改了查询以允许ResultTransformer实例化MyDTO,瞧!问题解决了。以下是我们修改过的查询和DTO类:

"select t1.data from mytable t1"

public class MyDTO<T> {  
    private MyWrapperClass wrapper;  

    public MyDTO(Object[] fields, WrapperFactory<T> wrapperFactory) {
        T data = (T) fields[0];        
        wrapper = wrapperFactory.newWrapper(data);
    }
}

根据我对纪尧姆的评论,拦截器并没有像希望的那样工作。大概是因为MyDTO不是一个持久的阶级。

我们还尝试让DTO直接通过单例类访问ApplicationContext,然后从那里获取WrapperFactory。虽然这很有效,但可以预见的是我们的单元测试已经结束,我们取消了这种方法。