2015-04-26 10 views
5

stworzyliśmy klasę abstrakcyjną, które używamy do czynienia z Redis (set/get wartości), który wygląda jak następuje:rodzajowych Java i Serializable

public abstract class AbstractCachedSupport<T extends Serializable> { 
    protected T get(CacheKey key, Supplier<T> supplier) {...} 
    // ... 
} 

Co nie jestem zadowolony, że nie możemy używać interfejsy, takie jak listy, mapa przy przedłużaniu tej klasy:

public class CachedMap extends AbstractCachedSupport<Map<String, Integer>> 

ponieważ nie rozciągają Serializable, więc musimy zawsze używać konkretnych klas:

public class CachedMap extends AbstractCachedSupport<HashMap<String, Integer>> 

Nie trzeba dodawać, że ma to swój udział w problemach, na przykład podczas migracji z jednej konkretnej klasy do drugiej. Nie jest to też coś, co nazwałbym najlepszą praktyką, ale może to tylko ja.

Alternatywą, która daje nam elastyczność pracy z interfejsami byłoby usunąć ograniczone pisanie i sprawdzić przy starcie czy T rozciąga Serializable:

public abstract class AbstractCachedSupport<T> { 
    public AbstractCachedSupport() { 
     final Class<T> type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
     if (!Serializable.class.isAssignableFrom(type)) { 
      throw new RuntimeException("T must extend Serializable"); 
     } 
    } 

    protected T get(CacheKey key, Supplier<T> supplier) {...} 
    // ... 
} 

To pozostawia nas bez kompilacji sprawdzanie na T rozszerzenie Serializable, też nie jest to miłe.

Czy znasz inny sposób, w jaki możemy rozwiązać ten problem w sposób elegancki? Czy wolisz używać pierwszego (ograniczonego parametru typu) lub drugiego (tylko sprawdzanie w czasie wykonywania)?

Kompromis byłby pójść na pierwszy i zawsze użyć klasy pojemnik do przechowywania kolekcji:

public class IntegerParamsContainer implements Serializable { 
    private static final long serialVersionUID = 1L; 
    private Map<String, Integer> map; 
} 

public class CachedMap extends AbstractCachedSupport<IntegerParamsContainer> 

Ale to musi w końcu ten sam problem co drugie: nie ma czasu kompilacji sprawdzanie , odpowiedzialność spoczywa na barkach programistów, aby zawsze korzystali z kolekcji, które implementują Serializable.

Edit: Część zajęć rozciągających AbstractCachedSupport są Wiosna (wersja 4,1 obecnie) zajęcia składników i nie są one nazywane CachedMap lub coś podobnego, raczej CityAutocompleteDataBean, WrParamsDataBean etc .. Jeśli dodamy do tych klas generycznych komponentów będziemy skończyć z deklaracji, takich jak:

@Inject 
private CityAutocompleteDataBean<ArrayList<String>>; 
@Inject 
private WrParamsDataBean<HashMap<String, WrData>>; 

w przeciwieństwie do

@Inject 
private CityAutocompleteDataBean; 
@Inject 
private WrParamsDataBean; 

Przyczyna użycia <ArrayList<String>> i <HashMap<String, WrData>> pozwoli uciec większości programistów, gdy zobaczą takie linie kodu. Uważam też, że jest to dość brzydkie, biorąc pod uwagę, od czego zaczęliśmy i czego używamy.

Mimo to działa to zgodnie z wnioskiem, dziękuję Jesper.

+0

Na marginesie, nie sądzę prace kontrolne run-time, czyli jeśli masz 'klasa CachedMap rozciąga AbstractCachedSupport > "masz ten sam problem, gdy argument' T' nie jest Serializable. To, czego faktycznie potrzebujesz do sprawdzenia, to wartości pól każdej instancji, a nie deklaracje. (Ale powinno być tak, że już to robi serializacja.) – Radiodef

Odpowiedz

5

Można to zrobić przy użyciu następującej składni:

public abstract class AbstractCachedSupport<T extends Serializable> { 
    // ... 
} 

public class CachedMap<T extends Map<String, Integer> & Serializable> 
     extends AbstractCachedSupport<T> { 
    // ... 
} 

Oznacza to, że typ T musi wdrożyć Map<String, Integer> a także Serializable.

Następnie można użyć CachedMap z konkretnym Map realizacji implementującej Serializable:

CachedMap<HashMap<String, Integer>> cachedMap = new CachedMap<>(); 
+0

Pokonałeś mnie, miałem zamiar opublikować to :) – Joffrey

+0

Wymagałoby to Java 8? – CKing

+1

@bot Nie, to nie wymaga Java 8. – Jesper