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.