我对instanceof对象使用开关盒有一个问题:
例如:我的问题可以用Java复制:
if(this instanceof A)
    doA();
else if(this instanceof B)
    doB();
else if(this instanceof C)
    doC():
如何使用实施switch...case?
我对instanceof对象使用开关盒有一个问题:
例如:我的问题可以用Java复制:
if(this instanceof A)
    doA();
else if(this instanceof B)
    doB();
else if(this instanceof C)
    doC():
如何使用实施switch...case?
Answers:
这是子类型多态性有帮助的典型方案。请执行下列操作
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()上this。
如果您不能随意更改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;
}
              只需创建一个Map,其中class是键,而功能即lambda或类似值就是值。
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();
如果需要检查异常,则可以实现抛出该异常并使用它而不是Runnable的FunctionalInterface。
instanceof,而且不幸的是,我的情况不是很容易适应其中之一)那个盒子...)
                    万一有人阅读,以防万一:
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(...)方法
注意:此模式在Joshua's Bloch“有效Java(第二版)”中进行了描述
@Override需要的每个实现以上doAction()?
                    action使用哪个?通过外部级联调用someFunction()正确的action?这只是增加了另一个间接级别。
                    你不能 该switch语句只能包含case作为编译时间常数并且其结果为整数的语句(最多Java 6和Java 7中的字符串)。
您正在寻找的内容在功能编程中称为“模式匹配”。
就像在最前面的答案中讨论的那样,传统的OOP方法是使用多态而不是切换。这个技巧甚至有一个记录良好的重构模式:用多态替换条件。每当我采用这种方法时,我都会喜欢实现一个Null对象以提供默认行为。
从Java 8开始,我们可以使用lambda和泛型为我们提供一些功能程序员非常熟悉的东西:模式匹配。它不是核心语言功能,但是Javaslang库提供了一种实现。来自javadoc的示例:
Match.ofType(Number.class)
    .caze((Integer i) -> i)
    .caze((String s) -> new BigDecimal(s))
    .orElse(() -> -1)
    .apply(1.0d); // result: -1
它不是Java世界中最自然的范例,因此请谨慎使用。尽管通用方法使您不必强制转换匹配的值,但是例如,缺少像Scala的case类那样分解匹配对象的标准方法。
我知道这已经很晚了,但对于将来的读者来说...
上面的方法当心仅基于该名称类的一,乙,Ç ...:
除非您可以保证A,B,C ...(Base的所有子类或实现者)是最终的,否则将不处理A,B,C ...的子类。
即使if,elseif,elseif .. 方法对于大量的子类/实现者来说较慢,它也更准确。
不幸的是,由于switch-case语句需要一个常量表达式,因此不可能开箱即用。为了克服这个问题,一种方法是将枚举值与类名一起使用,例如
public enum MyEnum {
   A(A.class.getName()), 
   B(B.class.getName()),
   C(C.class.getName());
private String refClassname;
private static final Map<String, MyEnum> ENUM_MAP;
MyEnum (String refClassname) {
    this.refClassname = refClassname;
}
static {
    Map<String, MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
    for (MyEnum instance : MyEnum.values()) {
        map.put(instance.refClassname, instance);
    }
    ENUM_MAP = Collections.unmodifiableMap(map);
}
public static MyEnum get(String name) {
    return ENUM_MAP.get(name);
 }
}
这样就可以像这样使用switch语句
MyEnum type = MyEnum.get(clazz.getName());
switch (type) {
case A:
    ... // it's A class
case B:
    ... // it's B class
case C:
    ... // it's C class
}
              不,没有办法做到这一点。但是,您可能要做的就是将多态性视为处理此类问题的一种方式。
像这样使用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() }
}
              这样可以更快地工作,并在情况
比较多的情况下通知您
-流程在性能敏感的上下文中执行  
public <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());
    }
}
              我个人喜欢以下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
示例代码使用字符串,但是您可以使用任何对象类型,包括Class。例如.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);
}
              Java现在允许您以OP的方式进行切换。他们称其为模式匹配开关。它目前处于草案阶段,但是我看到他们最近在交换机中投入了多少工作,我认为它将完成。JEP中给出的示例是
String formatted;
switch (obj) {
    case Integer i: formatted = String.format("int %d", i); break;
    case Byte b:    formatted = String.format("byte %d", b); break;
    case Long l:    formatted = String.format("long %d", l); break;
    case Double d:  formatted = String.format("double %f", d); break;
    case String s:  formatted = String.format("String %s", s); break
    default:        formatted = obj.toString();
}  
或使用其lambda语法并返回一个值
String formatted = 
    switch (obj) {
        case Integer i -> String.format("int %d", i)
        case Byte b    -> String.format("byte %d", b);
        case Long l    -> String.format("long %d", l); 
        case Double d  -> String.format("double %f", d); 
        case String s  -> String.format("String %s", s); 
        default        -> obj.toString();
    };
无论哪种方式,他们一直在用开关做一些很酷的事情。
如果可以操纵公共接口,则可以添加一个枚举,并让每个类返回唯一值。您将不需要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,则可以为枚举放入字符串值,并且switch case块仍将起作用。
value如果您只想区分枚举常量,则该字段是多余的-您可以直接使用常量(就像您一样)。
                    这个怎么样 ?
switch (this.name) 
{
  case "A":
    doA();
    break;
  case "B":
    doB();
    break;
  case "C":
    doC();
    break;
  default:
    console.log('Undefined instance');
}
              this.getSimpleName()不确定发帖人是否与JS混淆(是的,他正在使用控制台,呵呵)。
                    我认为有理由使用switch语句。如果您使用的是xText生成的代码,则可能是。或另一种EMF生成的类。
instance.getClass().getName();
返回类实现名称的字符串。即:org.eclipse.emf.ecore.util.EcoreUtil
instance.getClass().getSimpleName();
返回简单的表示形式,即:EcoreUtil
switch作为case条件使用,因为它不是恒定值
                    如果您需要通过“此”对象的类类型“切换”,则此答案是最好的https://stackoverflow.com/a/5579385/2078368
但是,如果您需要将“ switch”应用于任何其他变量。我建议另一种解决方案。定义以下接口:
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;
    }
    ...
}
您唯一需要关心的是-在实现ClassTypeInterface的所有类中保持“类型”唯一。这不是一个大问题,因为在任何交集的情况下,您都会收到“ switch-case”语句的编译时错误。
TYPE,还可以使用枚举,并且可以保证唯一性(如本答案所示)。但是,使用任何一种方法都必须在重命名时在两个地方进行重构。
                    TYPE = "A"。特别是如果它不在相应的类中,则手动进行操作时可能也会忘记它。IntelliJ实际上还可以在字符串或注释中找到类名称的出现,但这只是文本搜索(而不是查看语法树),因此包含误报。
                    这是使用http://www.vavr.io/在Java 8中完成此功能的功能方法
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)
        );
    }
              虽然不可能编写switch语句,但是可以为每种给定类型扩展到特定的处理。一种方法是使用标准的双重调度机制。我们要根据类型“切换”的示例是Jersey异常映射器,其中我们需要将大量异常映射到错误响应。尽管对于这种特定情况,可能有更好的方法(即使用将每个异常转换为错误响应的多态方法),但使用双调度机制仍然有用且实用。
interface Processable {
    <R> R process(final Processor<R> processor);
}
interface Processor<R> {
    R process(final A a);
    R process(final B b);
    R process(final C c);
    // for each type of Processable
    ...
}
class A implements Processable {
    // other class logic here
    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}
class B implements Processable {
    // other class logic here
    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}
class C implements Processable {
    // other class logic here
    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}
然后,在需要“开关”的任何地方,您可以按以下步骤进行操作:
public class LogProcessor implements Processor<String> {
    private static final Logger log = Logger.for(LogProcessor.class);
    public void logIt(final Processable base) {
        log.info("Logging for type {}", process(base));
    }
    // Processor methods, these are basically the effective "case" statements
    String process(final A a) {
        return "Stringifying A";
    }
    String process(final B b) {
        return "Stringifying B";
    }
    String process(final C c) {
        return "Stringifying C";
    }
}
              用类名创建一个枚举。
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;
        }
    }
}
希望这可以帮助。
Eclipse Modeling Framework有一个有趣的想法,也考虑了继承。基本概念在Switch 接口中定义:切换是通过调用doSwitch方法来完成的。
真正有趣的是实现。对于每种兴趣类型,
public T caseXXXX(XXXX object);
方法必须实现(默认实现返回null)。该doSwitch实现将尝试呼叫人的caseXXX其所有类型的层次结构中的对象的方法。符合以下条件的东西:
BaseType baseType = (BaseType)object;
T result = caseBaseType(eAttribute);
if (result == null) result = caseSuperType1(baseType);
if (result == null) result = caseSuperType2(baseType);
if (result == null) result = caseSuperType3(baseType);
if (result == null) result = caseSuperType4(baseType);
if (result == null) result = defaultCase(object);
return result;
实际的框架为每个类使用一个整数id,因此逻辑实际上是一个纯开关:
public T doSwitch(Object object) {
    return doSwitch(object.class(), eObject);
}
protected T doSwitch(Class clazz, Object object) {
    return doSwitch(getClassifierID(clazz), object);
}
protected T doSwitch(int classifierID, Object theObject) {
    switch (classifierID) {
    case MyClasses.BASETYPE:
    {
      BaseType baseType = (BaseType)object;
      ...
      return result;
    }
    case MyClasses.TYPE1:
    {
      ...
    }
  ...
您可以查看ECoreSwitch的完整实现,以获得更好的主意。
有一种更简单的方法来模拟使用instanceof的开关结构,您可以通过在方法中创建代码块并将其命名为标签来实现。然后,使用if结构模拟case语句。如果情况属实,则可以使用中断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;
            }
        }
              if... else if代码好吗?
                    if... else if,这是在Java之类的语言中实现控制流的错误方法。