Шаблон для специфичных для версии реализаций класса Java - PullRequest
5 голосов
/ 20 мая 2010

Так вот моя загадка. Я программирую инструмент, который должен работать на старых версиях нашего приложения. У меня есть код приложения, но я не могу изменить ни один из классов. Чтобы извлечь информацию из нашей базы данных, у меня есть своего рода DTO, который заполняется Hibernate. Он использует объект данных для версии 1.0 нашего приложения, хитро названный DataObject. Ниже приведен класс DTO.

public class MyDTO {  
    private MyWrapperClass wrapper;  

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

DTO создается с помощью запроса Hibernate следующим образом:

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, поэтому я не могу @Autowire зависимостью в Spring.

Я хотел бы повторно использовать MyDTO (и мои десятки других DTO) для обеих версий инструмента, без дублирования класса. Не повторяйся и все такое. Я уверен, что есть очень простой шаблон, который мне не хватает, который бы помог. Есть предложения?

Ответы [ 2 ]

1 голос
/ 20 мая 2010

Вы можете использовать Hibernate Interceptor и агрегат instantiate(String entityName, EntityMode entityMode, Serializable id).

В этом методе вы можете передать MyWrapperClass вашему объекту данных. В зависимости от версии вашего приложения, оболочка будет отличаться. Перехватчик может быть установлен на уровне сеанса или на уровне фабрики сеанса.

0 голосов
/ 28 мая 2010

Мы с коллегой перепробовали много вариантов. Мы остановились на использовании плохо документированного интерфейса ResultTransformer в Hibernate (на самом деле, Hibernate, отсутствие документации там постыдно). Хотя использование Transformer заставило нас вручную проанализировать массив Object [] в нашем конструкторе MyDTO, это был достойный компромисс.

В ResultTransformer мы внедрили специфичный для версии WrapperFactory через Spring. Мы изменили наши запросы, чтобы 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. Хотя это и сработало, но, как и следовало ожидать, мы проверили наши модульные тесты, и мы отказались от подхода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...