Mam pytanie o użycie skrzynki rozdzielczej dla instanceof
obiektu:
Na przykład: mój problem można odtworzyć w Javie:
if(this instanceof A)
doA();
else if(this instanceof B)
doB();
else if(this instanceof C)
doC():
Jak można to zaimplementować za pomocą switch...case
?
java
switch-statement
instanceof
olidev
źródło
źródło
Odpowiedzi:
Jest to typowy scenariusz, w którym pomaga polimorfizm podtypu. Wykonaj następujące czynności
Następnie można po prostu zadzwonić
do()
nathis
.Jeśli nie masz możliwości zmiany
A
,B
iC
możesz zastosować wzór odwiedzin, aby osiągnąć to samo.źródło
jeśli absolutnie nie możesz kodować do interfejsu, możesz użyć wyliczenia jako pośrednika:
źródło
Wystarczy utworzyć mapę, w której klasa jest kluczem, a funkcjonalność, tj. Lambda lub podobna, jest wartością.
// oczywiście zrefaktoryzuj to, aby zainicjować tylko raz
Jeśli potrzebujesz zaznaczonych wyjątków, zaimplementuj interfejs FunctionalInterface, który zgłasza wyjątek i użyj go zamiast Runnable.
źródło
instanceof
, i nie, mój scenariusz niestety nie jest jednym z tych, które łatwo pasują do to pudełko ...)Na wszelki wypadek, jeśli ktoś to przeczyta:
Najlepszym rozwiązaniem w java jest:
WIELKIE zalety takiego wzoru to:
Po prostu robisz to tak (żadnych przełączników):
W przypadku dodania nowej akcji o nazwie „d” MUSISZ zastosować metodę doAction (...)
UWAGA: Ten wzór jest opisany w Blos Joshua „Effective Java (2nd Edition)”
źródło
@Override
wymagane jest każde wdrożeniedoAction()
?action
się użyć? Przez zewnętrzną instancję kaskady, która dzwonisomeFunction()
z poprawnymaction
? To tylko dodaje kolejny poziom pośredni.Nie możesz
switch
Zestawienie może zawierać tylkocase
deklaracje, które są kompilacji stałe czasowe i które ocenia się całkowitą (do Java 6 i ciąg w Javie 7).To, czego szukasz, nazywa się „dopasowaniem wzorców” w programowaniu funkcjonalnym.
Zobacz także Unikanie instancji w Javie
źródło
Jak omówiono w najważniejszych odpowiedziach, tradycyjne podejście OOP polega na użyciu polimorfizmu zamiast zamiany. Istnieje nawet dobrze udokumentowany wzorzec refaktoryzacji dla tej sztuczki: Zamień warunkowy na polimorfizm . Ilekroć sięgam po to podejście, lubię również implementować obiekt Null, aby zapewnić domyślne zachowanie.
Począwszy od Java 8, możemy używać lambd i generics, aby dać nam coś, co programiści są bardzo obeznani z: dopasowaniem wzorców. To nie jest podstawowa funkcja języka, ale biblioteka JavaScript zapewnia jedną implementację. Przykład z javadoc :
To nie jest najbardziej naturalny paradygmat w świecie Java, więc używaj go ostrożnie. Chociaż ogólne metody pozwolą ci uniknąć konieczności typowania wartości dopasowanej, brakuje nam standardowego sposobu dekompozycji dopasowanego obiektu, jak na przykład w przypadku klas przypadków Scali .
źródło
Wiem, że jest bardzo późno, ale dla przyszłych czytelników ...
Uważaj na powyższe podejścia, które opierają się tylko na nazwie klasy A , B , C ...:
O ile nie możesz zagwarantować, że A , B , C ... (wszystkie podklasy lub realizatorzy Base ) są ostateczne, podklasy A , B , C ... nie będą rozpatrywane.
Chociaż podejście if, elseif, elseif .. jest wolniejsze dla dużej liczby podklas / implementatorów, jest bardziej dokładne.
źródło
Niestety nie jest to możliwe od razu po wyjęciu z pudełka, ponieważ instrukcja case-switch oczekuje stałego wyrażenia. Aby temu zaradzić, jednym ze sposobów byłoby użycie wartości wyliczeniowych z nazwami klas, np
Dzięki temu możliwe jest użycie instrukcji switch w ten sposób
źródło
Nie, nie ma na to sposobu. Możesz jednak rozważyć polimorfizm jako sposób na poradzenie sobie z tego rodzaju problemami.
źródło
Używanie instrukcji switch w ten sposób nie jest zorientowane obiektowo. Zamiast tego powinieneś użyć mocy polimorfizmu . Po prostu napisz
Po wcześniejszym skonfigurowaniu klasy podstawowej:
który jest klasą bazową dla
A
,B
iC
:źródło
Będzie to działało szybciej i sprawi, że w przypadku
- gdy masz stosunkowo wiele „przypadków”
- proces jest wykonywany w kontekście wrażliwym na wydajność
źródło
Nie możesz przełącznika działać tylko z typami bajtów, krótkich, char, int, String i wyliczonymi (i obiektowymi wersjami prymitywów, zależy to również od wersji java, ciągi można
switch
edytować w java 7)źródło
Osobiście podoba mi się następujący kod Java 1.8:
Wyjdzie:
W przykładowym kodzie zastosowano ciągi, ale można użyć dowolnego typu obiektu, w tym klasy. na przykład
.myCase(this.getClass(), (o) -> ...
Potrzebuje następującego fragmentu kodu:
źródło
Java pozwala teraz przełączać się w sposób OP. Nazywają to dopasowywanie wzorców dla przełącznika. Obecnie jest w fazie Draft, ale biorąc pod uwagę, ile pracy włożono ostatnio w przełączniki, myślę, że to przejdzie. Przykład podany w JEP to
lub używając ich składni lambda i zwracając wartość
tak czy inaczej robili fajne rzeczy z przełącznikami.
źródło
Jeśli możesz manipulować wspólnym interfejsem, możesz dodać wartość dodaną w wyliczeniu, a każda klasa zwróci unikalną wartość. Nie potrzebujesz instancji ani wzorca odwiedzającego.
Dla mnie logika musiała być zapisana w instrukcji switch, a nie sam obiekt. To było moje rozwiązanie:
ClassA, ClassB, and ClassC implement CommonClass
Berło:
Enum:
Impl:
Jeśli korzystasz z java 7, możesz wstawić wartości ciągu dla wyliczenia, a blok skrzynki przełączników będzie nadal działał.
źródło
value
Pole jest zbędny, jeśli tylko chcą odróżnić stałe enum - można bezpośrednio używać stałych (jak to zrobić).Co powiesz na to ?
źródło
this.getSimpleName()
Nie jestem pewien, czy plakat jest pomylony z JS (tak, używa konsoli, hehe).Myślę, że istnieją powody, aby używać instrukcji switch. Jeśli używasz kodu wygenerowanego xText, być może. Lub inny rodzaj klas generowanych przez EMF.
zwraca ciąg nazwy implementacji klasy. tj .: org.eclipse.emf.ecore.util.EcoreUtil
zwraca prostą reprezentację, tj .: EcoreUtil
źródło
switch
jakocase
warunku, ponieważ nie jest to stała wartośćJeśli potrzebujesz „przełączyć” typ klasy „tego” obiektu, ta odpowiedź jest najlepsza https://stackoverflow.com/a/5579385/2078368
Ale jeśli musisz zastosować „zmień” na dowolną inną zmienną. Sugerowałbym inne rozwiązanie. Zdefiniuj następujący interfejs:
Zaimplementuj ten interfejs w każdej klasie, którą chcesz „przełączyć”. Przykład:
Następnie możesz go użyć w następujący sposób:
Jedyną rzeczą, na którą powinieneś zwrócić uwagę - zachować unikalność „typów” we wszystkich klasach implementujących interfejs ClassTypeInterface. Nie jest to duży problem, ponieważ w przypadku jakiegokolwiek skrzyżowania pojawia się błąd czasu kompilacji dla instrukcji „case-case”.
źródło
TYPE
, możesz użyć wyliczenia, a unikalność jest gwarantowana (tak jak w tej odpowiedzi ). Jednak przy każdym z tych podejść będziesz musiał dokonać refaktoryzacji w dwóch miejscach po zmianie nazwy.TYPE = "A"
podczas zmiany nazwy. Zwłaszcza jeśli znajduje się poza odpowiednią klasą, można również zapomnieć o tym, wykonując to ręcznie. IntelliJ faktycznie znajduje również wystąpienia nazwy klasy w ciągach lub komentarzach, ale jest to po prostu wyszukiwanie tekstowe (zamiast patrzenia na drzewo składniowe), a zatem zawiera fałszywe alarmy.Oto funkcjonalny sposób na osiągnięcie tego w Javie 8 przy użyciu http://www.vavr.io/
źródło
Chociaż nie jest możliwe napisanie instrukcji switch, możliwe jest rozgałęzienie do określonego przetwarzania dla każdego danego typu. Jednym ze sposobów jest użycie standardowego mechanizmu podwójnej wysyłki. Przykładem, w którym chcemy „przełączyć” w zależności od typu, jest program mapujący wyjątek Jersey, w którym musimy zmapować wiele wyjątków od odpowiedzi na błędy. Chociaż w tym konkretnym przypadku istnieje prawdopodobnie lepszy sposób (tj. Zastosowanie metody polimorficznej, która tłumaczy każdy wyjątek na odpowiedź na błąd), użycie mechanizmu podwójnej wysyłki jest nadal przydatne i praktyczne.
Tam, gdzie kiedykolwiek potrzebny jest „przełącznik”, możesz to zrobić w następujący sposób:
źródło
Utwórz Enum z nazwami klas.
Znajdź nazwę klasy obiektu. Napisz skrzynkę przełączającą nad wyliczeniem.
Mam nadzieję że to pomoże.
źródło
Środowisko modelowania Eclipse ma interesujący pomysł, który uwzględnia również dziedziczenie. Podstawowa koncepcja została zdefiniowana w interfejsie Switch : przełączanie odbywa się poprzez wywołanie metody doSwitch .
Naprawdę ciekawe jest wdrożenie. Dla każdego rodzaju zainteresowania:
Metoda musi zostać zaimplementowana (z domyślną implementacją zwracającą wartość null). DoSwitch realizacja będzie próbował zadzwonić AL caseXXX metod na obiekcie dla całej jego rodzaj hierarchii. Coś w linii:
Rzeczywista struktura używa identyfikatora liczb całkowitych dla każdej klasy, więc logika jest w rzeczywistości czystym przełącznikiem:
Możesz spojrzeć na pełną implementację ECoreSwitch, aby uzyskać lepszy pomysł.
źródło
istnieje jeszcze prostszy sposób emulacji struktury przełącznika, który korzysta z instanceof. Robisz to, tworząc blok kodu w metodzie i nazywając go etykietą. Następnie używasz struktur if do emulacji instrukcji case. Jeśli przypadek jest prawdziwy, użyj przerwy LABEL_NAME, aby wyjść ze struktury prowizorycznego przełącznika.
źródło
if
...else if
kod podany przez OP?if
...else if
wyrażeniami „goto”, co jest złym sposobem na wdrożenie kontroli w takich językach jak Java.