19 ответов:
это типичный сценарий, где полиморфизм подтипа помогает. Сделайте следующее
interface I { void do(); } class A implements I { void do() { doA() } ... } class B implements I { void do() { doB() } ... } class C implements I { void do() { doC() } ... }затем вы можете просто позвонить
do()onthis.если вы не можете изменить
A,BиC, вы можете применить шаблон посетителя для достижения того же.
Если вы абсолютно не можете кодировать интерфейс, то вы можете использовать перечисление в качестве посредника:
public A() { CLAZZ z = CLAZZ.valueOf(this.getClass().getSimpleName()); switch (z) { case A: doA(); break; case B: doB(); break; case C: doC(); break; } } enum CLAZZ { A,B,C; }
на всякий случай, если кто-то прочтет его:
лучшее решение в java:
public enum Action { a{ void doAction(...){ // some code } }, b{ void doAction(...){ // some code } }, c{ void doAction(...){ // some code } }; abstract void doAction (...); }большие преимущества такой картины являются следующими:
вы просто делаете это как (никаких переключателей вообще):
void someFunction ( Action action ) { action.doAction(...); }в случае, если вы добавите новую акцию под названием "D" необходимо реализации doAction(...) метод
Примечание: этот шаблон описан в блоке Джошуа " эффективная Java (2-е издание)"
вы не можете.
switchзаявление может содержать толькоcaseоператоры, которые являются константами времени компиляции и которые вычисляют целое число (до Java 6 и строки в Java 7).то, что вы ищете, называется "шаблон" в функциональное программирование.
см. также избегая instanceof в Java
просто создайте карту, где класс является ключом, а функциональность, т. е. лямбда или аналогичная, является значением.
Map<Class,Runnable> doByClass = new HashMap<>(); doByClass.put(Foo.class, () -> doAClosure(this)); doByClass.put(Bar.class, this::doBMethod); doByClass.put(Baz.class, new MyCRunnable());// конечно, рефакторинг это только инициализировать один раз
doByClass.get(getClass()).run();Если вам нужны проверенные исключения, чем реализовать FunctionalInterface, который вызывает исключение и использовать его вместо Runnable.
Как обсуждалось в верхних ответах, традиционный подход ООП заключается в использовании полиморфизма вместо переключателя. Существует даже хорошо документированный шаблон рефакторинга для этого трюка: заменить условное на полиморфизм. Всякий раз, когда я достигаю этого подхода, мне нравится также реализовать null объект для обеспечения поведения по умолчанию.
начиная с Java 8, мы можем использовать лямбды и дженерики, чтобы дать нам что-то функциональное программисты очень знакомы с: сопоставление по образцу. Это не основная функция языка, но библиотека Javaslang обеспечивает одну реализацию. Пример из документация:
Match.ofType(Number.class) .caze((Integer i) -> i) .caze((String s) -> new BigDecimal(s)) .orElse(() -> -1) .apply(1.0d); // result: -1Это не самая естественная парадигма в мире Java, поэтому используйте ее с осторожностью. Хотя общие методы избавят вас от необходимости набирать сопоставленное значение, нам не хватает стандартного способа разложения сопоставленного объекта как с классы случая Scala например.
Я знаю, что это очень поздно, но для будущих читателей ...
остерегайтесь подходов выше, которые основаны только на имя класса A,B,C ... :
Если вы не можете гарантировать, что A,B,C ... (все подклассы или исполнители базовый) составляют финал тогда подклассы A,B, C ... не будет рассматриваться.
даже если если, elseif, elseif .. подход медленнее для большого количества подклассов / исполнителей, он более точен.
нет, нет никакого способа сделать это. То, что вы можете сделать, это, однако, рассмотреть полиморфизм как способ справиться с такого рода проблемами.
использование операторов switch, подобных этому, не является объектно-ориентированным способом. Вместо этого вы должны использовать силу полиморфизм. Просто напишите
this.do()предварительно настроив базовый класс:
abstract class Base { abstract void do(); ... }который является базовым классом для
A,BиC:class A extends Base { void do() { this.doA() } } class B extends Base { void do() { this.doB() } } class C extends Base { void do() { this.doC() } }
если вы можете управлять общим интерфейсом, вы можете добавить в перечисление и каждый класс возвращает уникальное значение. Вам не понадобится instanceof или шаблон посетителя.
для меня логика должна быть записана в инструкции switch, а не в самом объекте. Это было мое решение:
ClassA, ClassB, and ClassC implement CommonClassинтерфейс:
public interface CommonClass { MyEnum getEnumType(); }перечисление:
public enum MyEnum { ClassA(0), ClassB(1), ClassC(2); private int value; private MyEnum(final int value) { this.value = value; } public int getValue() { return value; }Impl:
... switch(obj.getEnumType()) { case MyEnum.ClassA: ClassA classA = (ClassA) obj; break; case MyEnum.ClassB: ClassB classB = (ClassB) obj; break; case MyEnum.ClassC: ClassC classC = (ClassC) obj; break; } ...если вы находитесь на java 7, Вы можете поставить строку значения для перечисления и блока корпуса коммутатора будут по-прежнему работать.
вы не можете переключатель работает только с байт, короткий, char, int, String и перечисляемых типов (и объектные версии примитивов, это также зависит от вашей версии java, строки могут быть
switched on в java 7)
Как насчет этого ?
switch (this.name) { case "A": doA(); break; case "B": doB(); break; case "C": doC(); break; default: console.log('Undefined instance'); }
мне лично нравится следующий код Java 1.8:
mySwitch("YY") .myCase("AA", (o) -> { System.out.println(o+"aa"); }) .myCase("BB", (o) -> { System.out.println(o+"bb"); }) .myCase("YY", (o) -> { System.out.println(o+"yy"); }) .myCase("ZZ", (o) -> { System.out.println(o+"zz"); });вывод:
YYyyпример кода использует строки, но вы можете использовать любой тип объекта, включая класс. например,
.myCase(this.getClass(), (o) -> ...требуется следующий фрагмент кода:
public Case mySwitch(Object reference) { return new Case(reference); } public class Case { private Object reference; public Case(Object reference) { this.reference = reference; } public Case myCase(Object b, OnMatchDo task) { if (reference.equals(b)) { task.task(reference); } return this; } } public interface OnMatchDo { public void task(Object o); }
Я думаю, что есть причины использовать оператор switch. Если вы используете xText сгенерированный код, возможно. Или другой вид ЭДС генерируемых классов.
instance.getClass().getName();возвращает строку имени класса реализации. я.е: орг.затмение.ЭДС.Ecore-моделью.утиль.EcoreUtil
instance.getClass().getSimpleName();возвращает простое представление, т. е.: EcoreUtil
Если вам нужно "переключиться" через тип класса" этого " объекта, этот ответ является лучшим https://stackoverflow.com/a/5579385/2078368
но если вам нужно применить "переключатель" к любой другой переменной. Я бы предложил другое решение. Определите следующий интерфейс:
public interface ClassTypeInterface { public String getType(); }реализуйте этот интерфейс в каждом классе, который вы хотите "переключить". Пример:
public class A extends Something implements ClassTypeInterface { public final static String TYPE = "A"; @Override public String getType() { return TYPE; } }после этого вы можете использовать его следующим образом:
switch (var.getType()) { case A.TYPE: { break; } case B.TYPE: { break; } ... }только вещь, о которой вы должны заботиться - сохранить "типы" уникальными во всех классах, реализующих Classstypeinterface. Это не большая проблема, потому что в случае любого пересечения вы получаете ошибку времени компиляции для оператора "switch-case".
существует еще более простой способ эмуляции структуры коммутатора, который использует instanceof, вы делаете это, создавая блок кода в своем методе и называя его меткой. Затем вы используете структуры if для эмуляции операторов case. Если случай истинен, то вы используете break LABEL_NAME, чтобы выйти из своей временной структуры коммутатора.
DEFINE_TYPE: { if (a instanceof x){ //do something break DEFINE_TYPE; } if (a instanceof y){ //do something break DEFINE_TYPE; } if (a instanceof z){ // do something break DEFINE_TYPE; } }
Это будет работать быстрее и сделать sence в случае
- вы не можете изменить классы моделей (внешняя библиотека)
- процесс выполняется в контексте производительности sencitive
- у вас относительно много "дел"public static <T> T process(Object model) { switch (model.getClass().getSimpleName()) { case "Trade": return processTrade(); case "InsuranceTransaction": return processInsuranceTransaction(); case "CashTransaction": return processCashTransaction(); case "CardTransaction": return processCardTransaction(); case "TransferTransaction": return processTransferTransaction(); case "ClientAccount": return processAccount(); ... default: throw new IllegalArgumentException(model.getClass().getSimpleName()); } }
создать перечисление С именами классов.
public enum ClassNameEnum { A, B, C }найти имя класса объекта. Написать переключатель случае за перечисление.
private void switchByClassType(Object obj) { ClassNameEnum className = ClassNameEnum.valueOf(obj.getClass().getSimpleName()); switch (className) { case A: doA(); break; case B: doB(); break; case C: doC(); break; } } }надеюсь, что это помогает.
вот функциональный способ его выполнения в Java 8 с помощью http://www.vavr.io/
import static io.vavr.API.*; import static io.vavr.Predicates.instanceOf; public Throwable liftRootCause(final Throwable throwable) { return Match(throwable).of( Case($(instanceOf(CompletionException.class)), Throwable::getCause), Case($(instanceOf(ExecutionException.class)), Throwable::getCause), Case($(), th -> th) ); }
Comments