Podczas niedawnej pracy w dużej firmie zauważyłem, że programiści stosowali ten styl kodowania:
Załóżmy, że mam funkcję, która zwraca 12, jeśli wejście to A, 21, jeśli wejście to B, i 45, jeśli wejście to C.
Więc mogę napisać podpis funkcji jako:
int foo(String s){
if(s.equals("A")) return 12;
else if(s.equals("B")) return 21;
else if(s.equals("C")) return 45;
else throw new RuntimeException("Invalid input to function foo");
}
Ale podczas przeglądu kodu poproszono mnie o zmianę funkcji na:
int foo(String s){
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("A", 12);
map.put("B", 21);
map.put("C", 45);
return map.get(s);
}
Nie mogę się przekonać, dlaczego drugi kod jest lepszy od pierwszego. Uruchomienie drugiego kodu zdecydowanie zajmie więcej czasu.
Jedynym powodem użycia drugiego kodu może być to, że oferuje on lepszą czytelność. Ale jeśli funkcja jest wywoływana wiele razy, to czy druga funkcja nie spowolni czasu działania narzędzia, które ją wywołuje?
Co o tym myślisz?
coding-style
coding-standards
Nikunj Banka
źródło
źródło
switch
wydaje się bardziej odpowiednia niżif-else
). Ale w pewnym momencie staje się problematyczne. Główną zaletą korzystania z mapy jest to, że można ją załadować z pliku lub tabeli itp. Jeśli kodujesz dane wejściowe na mapie, nie widzę dużej wartości nad przełącznikiem.Odpowiedzi:
Chodzi o to, aby przesunąć tworzenie mapy skrótów poza funkcję i zrobić to raz (lub tylko mniej razy niż w innym przypadku).
Jednak java od czasu java7 może mieć (końcowe) ciągi w przełącznikach:
źródło
W drugim przykładzie
Map
powinien to być prywatny element statyczny, aby uniknąć zbędnych kosztów inicjalizacji.W przypadku dużych ilości wartości mapa będzie działać lepiej. Korzystając z tablicy hasht, można wyszukać odpowiedź w stałym czasie. Konstrukcja wielokrotnego użycia musi porównywać dane wejściowe z każdą z możliwości, dopóki nie znajdzie właściwej odpowiedzi.
Innymi słowy, wyszukiwanie mapy to O (1), zaś
if
s to O (n), gdzie n jest liczbą możliwych danych wejściowych.Tworzenie mapy to O (n), ale jest wykonywane tylko raz, jeśli jest to stan statyczny stały. W przypadku często wykonywanego wyszukiwania mapa
if
w dłuższej perspektywie osiągnie lepsze wyniki niż instrukcje, kosztem nieco więcej czasu przy uruchamianiu programu (lub załadowaniu klasy, w zależności od języka).Biorąc to pod uwagę, mapa nie zawsze jest odpowiednim narzędziem do tego zadania. Jest to przydatne, gdy istnieje wiele wartości lub wartości muszą być konfigurowalne za pomocą pliku tekstowego, danych wejściowych użytkownika lub bazy danych (w takim przypadku mapa działa jak pamięć podręczna).
źródło
Oprogramowanie ma dwie prędkości: czas potrzebny na napisanie / odczyt / debugowanie kodu; i czas potrzebny do wykonania kodu.
Jeśli możesz mnie przekonać (i twoich recenzentów kodu), że funkcja skrótu jest rzeczywiście wolniejsza niż if / then / else (po refaktoryzacji w celu uzyskania statycznego skrótu) ORAZ możesz przekonać mnie / recenzentów, że została wywołana wystarczająco dużo razy, aby stworzyć rzeczywistą różnicę, a następnie idź naprzód i zamień skrót na if / else
W przeciwnym razie kod skrótu jest doskonale czytelny; i (prawdopodobnie) bezbłędny; możesz to szybko ustalić, patrząc na to. Nie można tak naprawdę powiedzieć tego samego o if / else, nie badając go naprawdę; różnica jest jeszcze bardziej przesadzona, gdy istnieją setki opcji.
źródło
Bardzo wolę odpowiedź w stylu HashMap.
Jest na to metryka
Istnieje metryka jakości kodu o nazwie Cyklomatyczna złożoność . Ta metryka zasadniczo liczy liczbę różnych ścieżek w kodzie ( jak obliczyć złożoność cykliczną ).
Dla każdej możliwej ścieżki wykonania metoda staje się coraz trudniejsza do zrozumienia ORAZ pełnego sprawdzenia poprawności.
Sprowadza się to do faktu, że „kontrolowanie słów kluczowych”, takich jak: ifs, elses, whiles itp., Wykorzystuje testy logiczne, które mogą być niepoprawne. Wielokrotne użycie „kontrolujących słów kluczowych” powoduje powstanie delikatnego kodu.
Dodatkowe korzyści
Ponadto „podejście oparte na mapie” zachęca programistów do myślenia o parach danych wejściowych i wyjściowych jako zestawie danych, który można wyodrębnić, ponownie wykorzystać, zmanipulować w czasie wykonywania, przetestować i zweryfikować. Na przykład poniżej przepisałem „foo”, abyśmy nie byli na stałe zamknięci w „A-> 12, B-> 21, C-> 45”:
rachet_freak wspomina o tym typie refaktora w swojej odpowiedzi, argumentuje za szybkością i ponownym użyciem, argumentuję za elastycznością środowiska wykonawczego (chociaż użycie niezmiennej kolekcji może mieć ogromne korzyści w zależności od sytuacji)
źródło
Dane są lepsze niż kod. Nie tylko dlatego, że dodawanie kolejnej gałęzi do kodu jest zbyt kuszące, ale dodanie wiersza do tabeli jest trudne do pomyłki. To pytanie jest niewielkim tego przykładem. Piszesz tablicę przeglądową. Napisz implementację z logiką warunkową i dokumentacją lub napisz tabelę, a następnie wyszukaj w niej.
Tabela danych jest zawsze lepszą reprezentacją niektórych danych niż kod, przechodzi optymalizacja modulo. To, jak trudna jest tabela do wyrażenia, może zależeć od języka - nie znam Javy, ale mam nadzieję, że zaimplementuje ona tablicę przeglądową prostszą niż przykład w OP.
To jest tabela odnośników w pythonie. Jeśli jest to postrzegane jako konflikt zapraszający, należy wziąć pod uwagę, że pytanie nie jest oznaczone java, refaktoryzacja jest niezależna od języka i że większość ludzi nie zna java.
Pomysł na restrukturyzację kodu w celu ograniczenia czasu działania ma swoją wartość, ale wolałbym raczej użyć kompilatora, który pobiera zwykłą konfigurację niż sam.
źródło