Wdrażamy adapter dla Jaxen (biblioteka XPath dla Java), który pozwala nam używać XPath do uzyskiwania dostępu do modelu danych naszej aplikacji.
Odbywa się to poprzez implementację klas, które mapują ciągi znaków (przekazane nam z Jaxen) na elementy naszego modelu danych. Szacujemy, że potrzebujemy około 100 klas z łącznie ponad 1000 ciągów porównań.
Myślę, że najlepszym sposobem na zrobienie tego jest prosta instrukcja if / else z ciągami zapisanymi bezpośrednio w kodzie - zamiast definiowania każdego z nich jako stałej. Na przykład:
public Object getNode(String name) {
if ("name".equals(name)) {
return contact.getFullName();
} else if ("title".equals(name)) {
return contact.getTitle();
} else if ("first_name".equals(name)) {
return contact.getFirstName();
} else if ("last_name".equals(name)) {
return contact.getLastName();
...
Jednak zawsze uczono mnie, że nie powinniśmy osadzać wartości ciągów bezpośrednio w kodzie, ale zamiast tego tworzyć stałe ciągów. To by wyglądało mniej więcej tak:
private static final String NAME = "name";
private static final String TITLE = "title";
private static final String FIRST_NAME = "first_name";
private static final String LAST_NAME = "last_name";
public Object getNode(String name) {
if (NAME.equals(name)) {
return contact.getFullName();
} else if (TITLE.equals(name)) {
return contact.getTitle();
} else if (FIRST_NAME.equals(name)) {
return contact.getFirstName();
} else if (LAST_NAME.equals(name)) {
return contact.getLastName();
...
W tym przypadku myślę, że to zły pomysł. Stała będzie kiedykolwiek używana w getNode()
metodzie tylko raz . Bezpośrednie korzystanie z ciągów jest tak samo łatwe do odczytania i zrozumienia, jak używanie stałych, i oszczędza nam pisania co najmniej tysiąca wierszy kodu.
Czy jest więc jakiś powód, aby definiować stałe ciągów dla pojedynczego użycia? Czy też dopuszczalne jest używanie ciągów bezpośrednio?
PS. Zanim ktokolwiek zasugeruje użycie zamiast tego wyliczeń, prototypowaliśmy to, ale konwersja wyliczenia jest 15 razy wolniejsza niż zwykłe porównywanie ciągów, więc nie jest brana pod uwagę.
Wniosek: poniższe odpowiedzi rozszerzyły zakres tego pytania poza zwykłe ciągi znaków, więc mam dwa wnioski:
- Prawdopodobnie w tym scenariuszu można używać bezpośrednio łańcuchów zamiast stałych ciągów, ale
- Istnieją sposoby na uniknięcie używania ciągów, co może być lepsze.
Więc wypróbuję technikę owijania, która całkowicie unika ciągów. Niestety nie możemy użyć instrukcji switch string, ponieważ nie korzystamy jeszcze z Java 7. Ostatecznie jednak uważam, że najlepszą odpowiedzią dla nas jest wypróbowanie każdej techniki i ocena jej wydajności. Rzeczywistość jest taka, że jeśli jedna technika jest wyraźnie szybsza, prawdopodobnie wybierzemy ją bez względu na jej piękno lub przestrzeganie konwencji.
źródło
switch
etykiety. Użyj przełącznika zamiastif
kaskad.Odpowiedzi:
Spróbuj tego. Wstępna refleksja jest z pewnością droga, ale jeśli zamierzasz jej używać wiele razy, co, jak sądzę, będziesz, z pewnością jest to lepsze rozwiązanie tego, co proponujesz. Nie lubię używać odbicia, ale używam go, gdy nie lubię alternatywy dla odbicia. Myślę, że to zaoszczędzi Twojemu zespołowi dużo bólu głowy, ale musisz podać nazwę metody (małymi literami).
Innymi słowy, zamiast przekazać „name”, należy przekazać „fullname”, ponieważ nazwa metody get to „getFullName ()”.
Jeśli potrzebujesz dostępu do danych zawartych w kontaktach, możesz rozważyć zbudowanie klasy opakowania dla kontaktu, która ma wszystkie metody dostępu do wymaganych informacji. Przydałoby się to również do zagwarantowania, że nazwy pól dostępu pozostaną zawsze takie same (tj. Jeśli klasa opakowania ma getFullName () i wywołujesz z pełną nazwą, zawsze będzie działać, nawet jeśli nazwa getFullName () kontaktu zostanie zmieniona - to spowodowałoby błąd kompilacji, zanim pozwoli ci to zrobić).
To rozwiązanie uratowało mnie kilka razy, a mianowicie gdy chciałem mieć jedną reprezentację danych do użycia w plikach danych jsf i kiedy dane te musiały zostać wyeksportowane do raportu za pomocą jaspera (który z mojego doświadczenia nie radzi sobie dobrze ze skomplikowanymi akcesoriami do obiektów) .
źródło
.invoke()
, ponieważ całkowicie usuwa stałe ciągów znaków. Nie przepadam za refleksją środowiska uruchomieniowego w celu skonfigurowania mapy, chociaż może wykonaniegetMethodMapping()
wstatic
bloku byłoby OK, więc dzieje się to przy starcie, a nie po uruchomieniu systemu.Jeśli to w ogóle możliwe, użyj Java 7, który pozwala na użycie ciągów w
switch
instrukcjach.From http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Nie mierzyłem, ale uważam, że instrukcje przełączania kompilują się do tabeli skoków zamiast długiej listy porównań. To powinno być jeszcze szybsze.
Odnośnie twojego rzeczywistego pytania: jeśli użyjesz go tylko raz , nie musisz przekształcać go w stałą. Zastanów się jednak, że stałą można udokumentować i wyświetlić w Javadoc. Może to być ważne w przypadku nietrywialnych wartości ciągu.
źródło
Jeśli zamierzasz to utrzymać (dokonać jakichkolwiek nietrywialnych zmian), mógłbym rozważyć użycie generowania kodu opartego na adnotacjach (być może za pomocą CGLib ), a nawet po prostu skryptu, który napisze cały kod za Ciebie. Wyobraź sobie liczbę literówek i błędów, które mogą wkraść się w rozważane podejście ...
źródło
object.getAddress().getCountry()
), co jest trudne do przedstawienia za pomocą adnotacji. Porównywania ciągów if / else nie są ładne, ale są szybkie, elastyczne, łatwe do zrozumienia i łatwe do testowania jednostkowego.Nadal używałbym stałych zdefiniowanych na szczycie twoich klas. To sprawia, że kod jest łatwiejszy w utrzymaniu, ponieważ łatwiej jest zobaczyć, co można zmienić później (w razie potrzeby). Na przykład
"first_name"
może stać"firstName"
się później.źródło
Jeśli twoje nazewnictwo jest spójne (aka
"some_whatever"
jest zawsze mapowanegetSomeWhatever()
), możesz użyć refleksji do ustalenia i wykonania metody get.źródło
Myślę, że przetwarzanie adnotacji może być rozwiązaniem, nawet bez adnotacji. Jest to rzecz, która może wygenerować dla Ciebie cały nudny kod. Minusem jest to, że otrzymasz N generowanych klas dla N klas modeli. Nie możesz również dodać niczego do istniejącej klasy, ale pisać coś w stylu
raz na zajęcia nie powinno stanowić problemu. Możesz też napisać coś takiego
we wspólnej nadklasie.
Do generowania kodu można użyć refleksji zamiast przetwarzania adnotacji. Minusem jest to, że musisz skompilować swój kod, zanim będziesz mógł użyć refleksji nad nim. Oznacza to, że nie możesz polegać na generowanym kodzie w swoich klasach modeli, chyba że wygenerujesz niektóre kody pośredniczące.
Rozważę także bezpośrednie wykorzystanie refleksji. Jasne, odbicie jest powolne, ale dlaczego jest powolne? To dlatego, że musi robić wszystko, co musisz zrobić, np. Włączyć nazwę pola.
źródło