switch 문에서 instanceof 연산자를 사용할 수 있습니까?


267

instanceof객체에 스위치 케이스를 사용하는 것에 대한 질문이 있습니다 .

예를 들어, 내 문제는 Java로 재현 될 수 있습니다.

if(this instanceof A)
    doA();
else if(this instanceof B)
    doB();
else if(this instanceof C)
    doC():

switch...case?를 사용하여 어떻게 구현할 수 있습니까?


6
실제로 스위치가 필요하다고 생각되면 클래스 이름을 int로 해시하고 사용할 수 있으며 충돌 가능성을 조심하십시오. 나는 이것이 실제로 사용 된 아이디어가 마음에 들지 않으므로 답변 대신 의견으로 추가하십시오. 어쩌면 실제로 필요한 것은 방문자 패턴입니다.
vickirk

1
Java 7부터 @vickirk가 지적한 해시 충돌을 피하기 위해 정규화 된 클래스 이름을 켤 수도 있지만 여전히 추악합니다.
Mitja

답변:


225

이것은 하위 유형 다형성이 도움이되는 일반적인 시나리오입니다. 다음을 수행하십시오

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, 당신은 동일을 달성하기 위해 방문자 패턴을 적용 할 수 있습니다.


33
방문자 패턴은 A, B 및 C가 방문자를 입력 매개 변수로 사용하는 추상 메소드를 사용하여 인터페이스를 구현해야한다는 것을 의미합니다. A, B, C를 변경할 수없고 이들 중 어느 것도 해당 인터페이스를 구현하지 않으면 어떻게됩니까?
thermz

21
방문자 패턴에 대한 마지막 설명이 잘못되었습니다. 여전히 A, B 및 C가 인터페이스를 구현해야합니다.
Ben Thurley

10
슬프게도 do () 코드가 호스트 환경을 요구하는 경우 (즉, do () 자체에없는 변수에 대한 액세스) 경우에는 작동하지 않습니다.
mafu

2
@mafu OP의 질문은 유형 기반 디스패치에 관한 것입니다. 문제를 파견하기 위해 do () 메소드에 더 많은 입력이 필요한 경우 여기에서 논의 된 질문의 범위를 벗어난 IMHO입니다.
jmg 2016 년

3
이 답변이 당신은 내가 점이 수정합니다없이이 작업을 수행하는 방법을 생각하면서를 A, B, C, B는 C가 그들이 세 번째 파트 라이브러리에있을 수 있기 때문에 클래스를 수정할 수 있다고 가정
cloudy_weather

96

인터페이스에 코드를 작성할 수 없다면 열거 형을 중개자로 사용할 수 있습니다.

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;

}

thx, 나는 또한 약간의 변경을해야했다 : 1) 각 참조 ID를 클래스 참조로 초기화하십시오. 2) 열거 형 id .toString ()으로 클래스 단순 이름을 지정하십시오. 3) 열거 형 ID 당 저장된 클래스 참조를 통해 열거 형을 찾으십시오. 나는 이것이 또한 난독 화 안전하다고 생각합니다.
물병 자리 힘

this.getClass (). getSimpleName ()이 CLAZZ 값과 일치하지 않으면 예외가 발생합니다. try catch 블록으로 둘러싸는 것이 좋으며 예외는 "default"또는 "else"옵션으로 처리됩니다. 스위치
tetri

40

클래스가 핵심이고 기능, 즉 람다 등이 값인 맵을 작성하십시오.

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를 구현하는 것보다 확인 된 예외가 필요한 경우.


3
특히 리팩토링이 용이 한 최고의 솔루션 imho.
Feiteira

2
이 솔루션의 유일한 단점은 람다에서 로컬 (메소드) 변수를 사용할 수 없다는 것입니다 (물론 필요할 수 있다고 가정).
zapatero 2016 년

1
@zapatero Runnable 대신 Function으로 변경하고 인스턴스를 매개 변수로 전달한 다음 필요할 때 캐스팅 할 수 있습니다.
Novaterata

공감; 이것은 실제로 OP가 요구하는 것을 수행하는 데 도움이되는 몇 가지 답변 instanceof중 하나입니다. 그 상자 ...)
Per Lundberg

@ SergioGutiérrez 감사합니다. 이 패턴은 외부 라이브러리에서만 필요합니다. 그런 다음 어댑터 구현으로 인터페이스를 만들 수도 있지만, 행동 DIFF가보다 분명해지기를 원하는 경우에 유용합니다. 유창한 주석 API 라우팅과 비슷합니다.
Novaterata

36

누군가가 그것을 읽을 경우를 대비하여 :

자바에서 가장 좋은 해결책은 다음과 같습니다.

public enum Action { 
    a{
        void doAction(...){
            // some code
        }

    }, 
    b{
        void doAction(...){
            // some code
        }

    }, 
    c{
        void doAction(...){
            // some code
        }

    };

    abstract void doAction (...);
}

이러한 패턴의 큰 장점은 다음과 같습니다.

  1. 당신은 그것을 좋아합니다 (아무것도 스위치 없음) :

    void someFunction ( Action action ) {
        action.doAction(...);   
    }
  2. "d"라는 새로운 액션을 추가하는 경우 반드시 doAction (...) 메소드를 구현해야합니다.

참고 :이 패턴은 Joshua의 Bloch "Effective Java (2 판)"에 설명되어 있습니다.


1
좋은! 을인가 @Override의 각 구현 위의 요구 doAction()?
mateuscb

9
이것이 어떻게 "BEST"솔루션입니까? 사용할 것을 어떻게 결정 action하시겠습니까? 캐스케이드 외부 인스턴스 someFunction()에 의해 올바른 action? 이것은 단지 다른 수준의 간접 지향을 추가합니다.
PureSpider

1
아니요, 런타임시 자동으로 수행됩니다. someFunction (Action.a)을 호출하면 a.doAction이 호출됩니다.
se.solovyev

11
나는 이것을 이해하지 못한다. 사용할 열거 형을 어떻게 알 수 있습니까? @PureSpider가 말했듯이 이것은 또 다른 수준의 작업처럼 보입니다.
James Manes

2
a, b 또는 C의 클래스 인스턴스를이 열거 형에 매핑하는 방법과 같은 완전한 예제를 제공하지 않은 것은 매우 슬픈 일입니다 . 이 Enum에 인스턴스를 캐스팅하려고합니다.
Tom

21

당신은 할 수 없습니다. switch문은 포함 할 수 있습니다 case컴파일 시간 상수 및 정수 (자바 6까지 자바 7의 문자열)에 대한 평가 문을.

함수형 프로그래밍에서 찾고있는 것을 "패턴 일치"라고합니다.

참조 자바 instanceof를 방지


1
아니요, 대부분의 기능적 언어에서는 유형에 대해서만 패턴 일치를 만들 수 없으며 생성자에서만 패턴 일치를 할 수 없습니다. ML과 Haskell에서는 적어도 사실입니다. Scala와 OCaml에서는 가능하지만 패턴 일치의 일반적인 적용은 불가능합니다.
jmg

물론, 생성자에 대한 검사는 위에서 설명한 시나리오와 "동일"합니다.
Carlo V. Dango

1
경우에 따라서는 일반적이지 않습니다.
jmg

스위치는 열거 형도 지원할 수 있습니다.
Solomon Ucko

다른 언어를 볼 수는 없다.
L. Blanc

17

최고의 답변에서 논의 된 바와 같이, 전통적인 OOP 방식은 스위치 대신 다형성을 사용하는 것입니다. 이 트릭에는 잘 문서화 된 리팩토링 패턴이 있습니다 : 조건부를 다형성으로 바꾸기 . 이 접근법에 도달 할 때마다 기본 동작을 제공하기 위해 Null 객체 를 구현하고 싶습니다 .

Java 8부터는 람다와 제네릭을 사용하여 함수형 프로그래머에게 익숙한 패턴 매칭을 제공 할 수 있습니다. 핵심 언어 기능은 아니지만 Javaslang 라이브러리 는 하나의 구현을 제공합니다. javadoc의 예 :

Match.ofType(Number.class)
    .caze((Integer i) -> i)
    .caze((String s) -> new BigDecimal(s))
    .orElse(() -> -1)
    .apply(1.0d); // result: -1

Java 세계에서 가장 자연스러운 패러다임이 아니므로주의해서 사용하십시오. 일반적인 메소드는 일치하는 값을 타입 캐스트하지 않아도되지만, 우리는 스칼라의 사례 클래스 와 같이 일치하는 객체를 분해하는 표준 방법이 없습니다 .


9

나는 이것이 매우 늦었지만 장래 독자들을 위해 ...

A , B , C ... 클래스의 이름 에만 기반한 위의 접근 방식에주의하십시오 .

당신은 보장 할 수없는 한 A는 , B , C가 ... (모든 서브 클래스 또는 구현 자료가 ) 있습니다 마지막 의 다음 서브 클래스 , B , C가 ... 처리되지 않습니다.

많은 수의 서브 클래스 / 구현자가 if, elseif, elseif .. 접근 방식이 느리 더라도 더 정확합니다.


실제로, 다형성 (일명 OOP)
Val

8

불행히도 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
}

JEP 문제 8213076이 완전히 구현 될 때까지 대상 클래스를 수정하지 않고 유형을 기반으로 스위치 문을 얻는 가장 확실한 방법이라고 생각합니다.
Rik Schaaf

5

아니요,이 방법은 없습니다. 그러나 당신이하고 싶은 것은 다형성 을 이런 종류의 문제를 처리하는 방법으로 간주 하는 것입니다.


5

이와 같은 스위치 문을 사용하는 것은 객체 지향 방식이 아닙니다. 대신 다형성 의 힘을 사용해야합니다 . 간단히 쓰기

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() }
}

@jmg 는 추상 기본 클래스 대신 인터페이스를 사용하여 제안합니다 ( stackoverflow.com/questions/5579309/switch-instanceof/… ). 일부 상황에서는 더 우수 할 수 있습니다.
Raedwald

5


상대적으로 많은 '케이스'
가있는 경우 성능이 중요한 상황에서 프로세스가 실행되는 경우 더 빠르게 작동하고 문장을 만듭니다.

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());
    }
}

1
구현 클래스는 스위치에 사용되는 경우이 만 작동하기 때문에 이것은의 인스턴스를하고 같은 아니지만, 인터페이스에 대한 작동하지 않습니다 / abstractclass / 슈퍼
lifesoordinary

그래, 이것은 아니다
Mike

노력하지만, @lifesoordinary의 의견을 제외 하고는이 답변이 클래스 참조 대신 하드 코딩 된 문자열을 사용하기 때문에 일반적으로 가지고있는 typesafety를 놓치게됩니다. 그것은 당신이 여기에 다른 패키지 names.Edit와 클래스 이름에 대한 어떠한 중복 인 경우 전체 정식 이름으로이 기능을 확장해야 할 것 특히, 오타를 만들기 위해 매우 쉽습니다 : (좀 내 지점을 증명) 고정 오타
릭 샤프

4

스위치는 byte, short, char, int, String 및 열거 유형에서만 작동 할 수 없습니다 (그리고 프리미티브의 객체 버전은 Java 버전에 따라 다르며 문자열은 switchJava 7에서 사용할 수 있음 )


Java 6에서는 문자열을 켤 수 없으며 "기본 버전의 객체 버전"을 켤 수 없습니다.
Lukas Eder

@ Bozho 나는 그것이 당신의 자바 버전에 달려 있다고 말했는데, Java 7에서는 Strings를 켤 수 있습니다.
Tnem

@Lukas Eder Java 사양을 확인하십시오
Tnem

4

개인적으로 다음 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);
}

4

이제 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();
}  

또는 그들의 람다 구문을 사용하고 값을 반환

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();
    };

어느 쪽이든 스위치로 멋진 작업을 수행했습니다.


3

공통 인터페이스를 조작 할 수 있으면 열거 형을 추가하고 각 클래스가 고유 한 값을 반환하도록 할 수 있습니다. 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을 사용하는 경우 열거 형에 문자열 값을 입력하면 스위치 케이스 블록이 계속 작동합니다.


value만 열거 상수를 구분하려면 필드는 중복 - 직접 상수를 사용할 수 있습니다 (당신처럼).
user905686

2

이건 어때요 ?

switch (this.name) 
{
  case "A":
    doA();
    break;
  case "B":
    doB();
    break;
  case "C":
    doC();
    break;
  default:
    console.log('Undefined instance');
}

3
이것은 Java 7에서만 작동한다는 것을 지적 this.getSimpleName()해야합니다. 포스터와 JS가 혼동되는지 확실하지 않습니다 (예, 그는 콘솔을 사용하고 있습니다).
pablisco

5
이것은 소스 코드 참조 투명성에서 벗어나는 문제가 있습니다. 즉, IDE에서 참조 무결성을 유지할 수 없습니다. 이름을 바꾸려고한다고 가정하십시오. 반사는 악하다.
Val

1
좋은 생각이 아닙니다. 클래스 로더가 여러 개인 경우 클래스 이름이 고유하지 않습니다.
Doradus

코드 압축과 관련하여 중단됨 (→ ProGuard)
Matthias Ronge

1

switch 문을 사용해야하는 이유가 있다고 생각합니다. xText 생성 코드를 사용하는 경우 가능합니다. 또는 다른 종류의 EMF 생성 클래스.

instance.getClass().getName();

클래스 구현 명의 캐릭터 라인을 돌려줍니다. 예 : org.eclipse.emf.ecore.util.EcoreUtil

instance.getClass().getSimpleName();

간단한 표현을 반환합니다. 예 : EcoreUtil


상수 값이 아니기 때문에 조건 switch으로 사용할 수 없습니다.case
B-GangsteR

1

"this"객체의 클래스 유형을 통해 "전환"해야하는 경우이 답변이 가장 좋습니다. 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;
    }
    ...
}

주의해야 할 것은-ClassTypeInterface를 구현하는 모든 클래스에서 "유형"을 고유하게 유지하는 것입니다. 교차점의 경우 "switch-case"문에 대해 컴파일 타임 오류가 발생하기 때문에 큰 문제는 아닙니다.


에 String을 사용하는 대신 TYPE열거 형을 사용할 수 있으며 고유성이 보장됩니다 ( 이 답변 에서 수행 된 것처럼 ). 그러나 접근 방법 중 하나를 사용하면 이름을 바꿀 때 두 곳에서 리팩토링해야합니다.
user905686

@ user905686 무엇의 이름을 바꾸시겠습니까? 현재 예제에서 "A"유형은 코드의 양을 최소화하기 위해 Something 클래스 내부에 정의되어 있습니다. 그러나 실제 생활에서는 분명히 외부에서 (일부 일반적인 장소에서) 정의해야하며 추가 리팩토링에는 아무런 문제가 없습니다.
Sergey Krivenkov

클래스 A의 이름을 바꾸는 것을 의미합니다. 이름을 바꿀 때 자동 리팩토링에 변수 TYPE = "A"가 포함되지 않을 수 있습니다 . 특히 해당 클래스 외부에있는 경우 수동으로 수행 할 때 잊어 버릴 수도 있습니다. IntelliJ는 실제로 문자열이나 주석에서 클래스 이름의 발생을 찾지 만 구문 트리를 보는 대신 텍스트 검색 일 뿐이므로 오 탐지를 포함합니다.
user905686

@ user905686 아이디어를 시각화하는 예제 일뿐입니다. 실제 프로젝트에서 유형 정의에 문자열을 사용하지 말고 정수 상수 (또는 열거 형)로 일부 MyTypes 클래스 홀더를 선언하고 ClassTypeInterface를 구현하는 클래스에서 사용하십시오.
Sergey Krivenkov

1

다음은 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)
        );
    }

1

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";
    }
}

이것은이 답변에서 이미 논의 된 방문자 패턴과 매우 유사합니다. stackoverflow.com/a/5579385
typeracer

0

클래스 이름으로 열거 형 을 만듭니다 .

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;
        }
    }
}

도움이 되었기를 바랍니다.


2
열거 형 상수와 클래스 사이의 연결이 명시 적으로 수행되는 이 방법 과 달리 클래스 이름으로 암시 적으로 연결을 수행합니다. 열거 형 상수 또는 클래스 중 하나의 이름 만 바꾸면 코드가 손상되지만 다른 방법은 여전히 ​​작동합니다.
user905686

0

Eclipse Modeling Framework에는 상속을 고려한 흥미로운 아이디어가 있습니다. 기본 개념은 스위치 인터페이스 에서 정의됩니다 . 전환은 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 의 완전한 구현을 살펴볼 수 있습니다 .


-1

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;
            }
        }

이것이 OP가 제공 한 if... else if코드 보다 나은 점은 무엇입니까?
typeracer

내 이전 의견을 자세히 설명하기 위해 : 제안하는 것은 본질적으로 if... else if을 "goto"문 으로 바꾸는 것입니다 . 이는 Java와 같은 언어로 제어 흐름을 구현 하는 잘못된 방법입니다.
typeracer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.