2010-05-20 26 views
5

Oto moja zagadka. Programuję narzędzie, które musi pracować nad starymi wersjami naszej aplikacji. Mam kod do aplikacji, ale nie mogę zmienić żadnej z klas. Aby wyciągnąć informacje z naszej bazy danych, mam DTO sortów zapełnionych przez Hibernate. Zużywa obiekt danych dla wersji 1.0 naszej aplikacji, sprytnie nazwany DataObject. Poniżej znajduje się klasa DTO.Wzór implementacji specyficznej dla wersji klasy Java

public class MyDTO { 
    private MyWrapperClass wrapper; 

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

DTO jest tworzony poprzez kwerendy hibernacji w następujący sposób:

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

Teraz trochę logika jest potrzebna w górnej części obiektu danych, więc zrobiłem klasy otoki dla niego. Zauważ, że DTO przechowuje instancję klasy opakowującej, a nie oryginalny obiekt danych.

public class MyWrapperClass { 

    private DataObject data; 

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

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

Działa to dobrze, dopóki nie będę musiał pracować nad wersją 2.0 naszej aplikacji. Teraz DataObject w dwóch wersjach jest bardzo podobny, ale nie taki sam. Spowodowało to różne podklasy MyWrapperClass, które implementują własną, własną wersję doSomethingImportant(). Wciąż dobrze. Ale w jaki sposób myDTO tworzy instancję odpowiedniej klasy MyWrapperClass specyficznej dla wersji? Hibernate z kolei tworzy instancję MyDTO, więc nie jest tak, że mogę @Autowire zależność na wiosnę.

Chciałbym ponownie wykorzystać MyDTO (i moje dziesiątki innych DTO) dla obu wersji narzędzia, bez konieczności kopiowania klasy. Nie powtarzaj siebie i tak dalej. Jestem pewna, że ​​brakuje bardzo prostego wzorca, który by mi pomógł. Jakieś sugestie?

Odpowiedz

0

Mój współpracownik i ja próbowaliśmy wielu opcji. Postanowiliśmy zastosować słabo udokumentowany interfejs ResultTransformer w Hibernate (naprawdę, Hibernate, brak dokumentacji jest haniebny). Chociaż użycie Transformera zmusiło nas do ręcznego przeanalizowania tablicy Object [] w naszym konstruktorze MyDTO, była to godna kompromis.

W ResultTransformer, wstrzykiwaliśmy specyficzny dla wersji WrapperFactory przez Spring. Zmieniliśmy nasze zapytania, aby umożliwić ResultTransformer tworzenie instancji MyDTO i voila! Problem rozwiązany. Poniżej przedstawiamy nasze zmodyfikowane zapytanie i DTO klasa:

"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); 
    } 
} 

Jak na moje komentarze do Guillaume kolektora nie działa, jak się spodziewano. Prawdopodobnie dlatego, że MyDTO nie jest trwałą klasą.

Próbowaliśmy również, aby DTO uzyskiwał dostęp do ApplicationContext bezpośrednio przez pojedynczą klasę, a następnie uzyskiwał WrapperFactory. Mimo że zadziałało, w przewidywalny sposób fubowało nasze testy jednostkowe, a my zrezygnowaliśmy z podejścia.

1

Możesz użyć Hibernuj Interceptor narzędzie instantiate(String entityName, EntityMode entityMode, Serializable id).

W tej metodzie można przekazać obiekt MyWrapperClass do obiektu danych. W zależności od wersji aplikacji opakowanie będzie inne. Przechwytywacz można ustawić na poziomie sesji lub na poziomie fabrycznym sesji.

+0

To nie działało dla nas, prawdopodobnie dlatego, że MyDTO nie jest trwałą klasą. Jedynymi wywołanymi metodami Interceptor były AfterTransactionBegin(), onPrepareStatement(), beforeTransactionCompletion() i afterTransactionCompletion(). Żadne z nich nie dało nam odpowiedniego okna do manipulowania danymi. Jednak ustawiłeś nas na właściwej ścieżce, gdy w końcu znaleźliśmy interfejs ResultTransformer Hibernate. Dzięki! –

+0

Fajnie, cieszę się, że mogłem pomóc trochę :) – Guillaume