2009-02-23 11 views
9

Załóżmy, że masz dwa wystąpienia tego samego typu fasoli i chcesz wyświetlić podsumowanie zmian między tymi dwoma wystąpieniami - na przykład masz komponent bean reprezentujący ustawienia użytkownika w aplikacji, a Ty " Chciałbyś móc wyświetlić listę zmian, które zostały zmienione w nowych ustawieniach, które przesyła użytkownik (instancja # 1) w porównaniu do tego, co jest już przechowywane dla użytkownika (instancja # 2).Wspólny algorytm generowania diff pól w dwóch komponentach bean?

Czy istnieje powszechnie używany algorytm lub wzorzec projektowy dla zadania takiego jak to, być może coś, co można wyodrębnić i ponownie użyć dla różnych rodzajów fasoli? (Trudno mi jest wymyślić dobre imię tego typu problemu, aby wiedzieć, co Google). Sprawdziłem commons-beanutils i nic nie wyskoczyło na mnie.

Odpowiedz

6

Jeśli mówisz o porównywaniu wartości, rozważyłbym zastosowanie refleksji i porównanie ich pola za polem.

coś takiego:


    Field[] oldFields = oldInstance.class.getDeclaredFields(); 
    Field[] newFields = newInstance.class.getDeclaredFields(); 
    StringBuilder changes = new StringBuilder(); 

    Arrays.sort(oldFields); 
    Arrays.sort(newFields); 

    int i = 0; 
    for(Field f : oldFields) 
    { 
     if(!f.equals(newFields[i])) 
     { 
      changes.append(f.getName()).append(" has changed.\n"); 
     } 
     i++; 
    } 

Kod ten nie został przetestowany. Możesz potrzebować uzyskać wartości w polach i porównać je zamiast porównywania pól ze sobą, ale powinno to działać teoretycznie.

+0

Wystąpił problem z tym kodem. Po pierwsze, zakłada, że ​​oldFields.length jest taki sam jak newFields.length. Potrzebujesz jakiejś logiki, aby określić zupełnie nowe pola i pola, których brakuje. Wreszcie, nie użyłbym pętli foreach, gdy i tak musisz zwiększyć licznik; po prostu użyj "na". –

+0

są to oba wystąpienia tej samej klasy, w jaki sposób ich liczba może być różna? – kgrad

+0

Ponadto, jeśli jest to jednowątkowe, powinieneś używać StringBuilder zamiast StringBuffer. – cdmckay

2

Odbicie nie zachowuje porządku pola w następnym wywołaniu: bezpieczniejsze jest porządkowanie tablic.

/* 
*declarations of variables 
*/ 

Arrays.sort(oldFields);//natural order - choice 1 
Arrays.sort(newFields, new Ordinator());//custom Comparator - choice 2 

/* 
*logic of comparations between elements 
*/ 

W wyborze 2 można zdecydować logikę sortowania (JAK Sortowanie elementów) z wewnętrznym klasy koordynator extending Comparator.

PS kod jest projekt

3

Robiliśmy coś podobnego z utils fasoli i to działało dobrze. Co należy wziąć pod uwagę: Czy drążysz obiekty pola? Jeśli osoba zawiera adres i zmiany adresu, czy mówisz, że adres się zmienił, czy adres.postalCode został zmieniony (mamy)? Czy zwrócisz listę właściwości, starej wartości, nowej wartości z pliku diff (my)? Jak chcesz obchodzić się z datami - jeśli wszystko, na czym ci zależy, jest częścią daty, to porównanie powinno zignorować czas? Jak powiedzieć, które pola należy zignorować?

To nie jest tak naprawdę kopia i wklej odpowiedź, ale więcej listy rzeczy, które nie były od razu oczywiste, kiedy napisaliśmy naszą różnicę.

Jeśli chodzi o implementację, mamy po prostu metodę statycznego wykorzystania, która pobiera dwa komponenty bean i listę właściwości do porównania, a następnie zwraca mapę właściwości do pary zawierającej starą wartość i nową wartość. Następnie każdy komponent bean ma metodę diff(Object o), która w razie potrzeby wywołuje metodę statycznego wykorzystania.

+0

Pracuję nad podobnym wymogiem. Przedstawione rozwiązanie wygląda interesująco. Czy mógłbyś udostępnić kod lub szczegóły algorytmu? Dzięki. – krishnakumarp

+1

Chciałbym móc, ale to było dwa zadania temu. Jednak dwa lata temu napisałem "Inspirowany przez" przykładowy kod do wywiadu. Nie robi tak wiele, jak oryginał, ale może być przydatny do inspiracji. [Pobierz] (http://stanford.edu/~pradtke/ObjectDiffer.zip) lub [przeglądaj] (http://stanford.edu/~pradtke/ObjectDiffer/). – Patrick

1

Dobre odpowiedzi powyżej.

Jeśli dane zmieniają się strukturalnie, tzn. Całe zbiory pól mogą być istotne lub nie, w zależności od innych, warto rozważyć differential execution.

Zasadniczo masz pętlę nad polami i serializujesz bieżące wartości pól w tym samym czasie, w którym deserializujesz poprzednie wartości, porównując je w trakcie.

Jeśli istnieje test warunkowy, który sprawia, że ​​blok pól jest istotny lub nie, należy serializować/deserializować wartość true lub false testu warunkowego i użyć go, aby zdecydować, czy serializować i/lub przekształcać do postaci szeregowej. dotknięte pola. I ładnie się powtarza.

Tylko sugestia.

+0

Dzięki za link, na pewno się tym zajrzę –

3

Te biblioteki powinny pomóc.

https://code.google.com/p/beandiff/ - Bibliotekę porównawczą opartą na adnotacjach. Licencja Apache 2.0

https://github.com/SQiShER/java-object-diff/ - Fasola różni się w zależności od wzorca odwiedzającego. Licencja Apache 2.0

Musieliśmy wygenerować różnicę między fasolami w formacie json dla celów audytu. W końcu wdrożyliśmy go przy użyciu biblioteki beandiff.

** EDYCJA ** Wygląda to na nowszą opcję. Jednak tego nie używałem.

http://beandiff.org/

Nadzieję, że to pomaga.

0

Rozwiązanie wykorzystujące odbicia i standardowe struktury danych.

Field[] declaredFields = ClassOne.class.getDeclaredFields(); 
    Field[] declaredFields2 = ClassTwo.class.getDeclaredFields(); 
    ArrayList<String> one = new ArrayList<String>(); 
    ArrayList<String> two = new ArrayList<String>(); 
    for (Field field : declaredFields) 
    { 
     one.add(field.getName()); 
    } 

    for (Field field : declaredFields2) 
    { 
     two.add(field.getName()); 
    } 

    List<String> preone = (List<String>)one.clone(); 

    one.removeAll(two); 
    two.removeAll(preone); 
    Collections.sort(one); 
    Collections.sort(two); 

    System.out.println("fields only in One : " + one); 
    System.out.println("fields only in Two : " + two); 
Powiązane problemy