2009-09-15 6 views
6

다른 경우에는 좋지 않은 경우 이외에 Java에서 스위치 케이스를 구현하는 대체 방법이 있습니까? 선택 사항에 따라 값 집합이 결합되어 실행됩니다.Java의 스위치 케이스에 대한 대안

+0

'한 세트의 값이 콤보로 표시됩니다'라고 할 때 무엇을 의미합니까? – Alterlife

+0

이미 비슷한 질문이 있습니다. http://stackoverflow.com/questions/126409/ways-to-eliminate-switch-in-code –

+0

@cdb : 왜 다시 부탁 했습니까? 이전 답변에서 알려주지 않은 내용은 무엇입니까? –

답변

15

아마도 상수의 요구 사항에 어려움을 겪고있을 것입니다. 일반적으로이 코드는 냄새지만, 할 수있는 일이 있습니다. 전환하려는 이유를 자세히 설명한 다른 질문을 제기하고 연결할 수도 있습니다. 위의 예에서

Map<String,Object> map = new HasMap<String,Object>(); 
// ... insert stuff into map 
// eg: map.add("something", new MyObject()); 

String key = "something"; 
if (map.contains(key)) { 
    Object o = map.get(key); 
} 

, 당신은이 모든 조회로 전환하게

interface Handler { 
    public void doSomething(); 
} 

처럼, '핸들러'에 뭔가를 매핑 할 수 있습니다.

if (map.contains(key)) { map.get(key).doSomething(); } 

다시 말하지만 약간의 냄새가 나기 때문에 추론을 설명하는 질문을 게시하십시오.

public interface Task<T> 
    { 
    public void doSomething(T context); 
    } 

public Class SwitchCase<T> 
    { 
    Map<Integer,Task<T>> tasks; 
    Task<T> defaultTask; 

    public void choose(int choice, T context) 
     { 
     Task<T> t= this.tasks.get(choice); 
     if(t!=null) { t.doSomething(context); return;} 
     if(defaultTask!=null) { defaultTask.doSomething(context);} 
     } 
    } 
+2

정수가 고통이라면 열거 형을 사용할 수도 있습니다. – Ibrahim

+0

이와 비슷한 것을 찾고 있습니다. –

+1

왜 포함하고지도에서 두 번 읽는가. 명령 설명 = map.get (key); if (null! = command) { ... command.execute(); } –

0

무엇을 하시겠습니까? 왜 Switch-Case가 충분하지 않습니까?

빠른 답은 경우 - 다른

0
if() {} 
    else if() {} 
... 
    else if() {} 

를 사용할 수 있습니까?

는하지만 ...

1

if,else if,else의 추악한 시리즈가 더 언급하지 않았다?

0

if (else ifelse과 함께) 문장은 어떻습니까? switch은 정수 또는 열거 유형에 대해 동등성을 사용하여 전환 만 허용하지만 if을 사용하면 부울 논리를 사용할 수 있습니다.

+0

char, byte, short도 스위치에 사용할 수 있습니다. – dogbane

+0

예, 안전하게 (자동) int로 캐스팅 할 수도 있습니다 –

4

코드를 리팩토링하여 다형성을 사용하면 switch 문이 필요하지 않을 수 있습니다. 그러나 스위치에 대한 합법적 인 사용법이 있으므로 상황에 따라 다릅니다.

+2

예 - 이것은 잘 알려진 리팩토링입니다. http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html – RichardOD

+0

좋은 링크. 카탈로그에 좋은 것들이 많이있는 것처럼 보입니다. –

0

언제든지 스위치를 if-else if-else if-else if...으로 바꿀 수는 있지만 원하는 이유는 없습니다. 문맥에 따라 switch 또한 때로는 배열이나 해시 맵으로 대체 될 수 있습니다.

24

코드 주위에 스위치/사례 설명이 많아서 당신을 미치게 만듭니다.

당신은 리팩토링을 선택할 수 있습니다 : Replace conditional with polymorphism.

의 당신이 다른 장치에 정보를 저장하는 데 사용되는 소프트웨어의 조각 있다고 가정 해 봅시다 : 4 개 지속성 작업이 정의됩니다 삭제, 가져 오기 저장을, 업데이트은 N 개의 지속성 메커니즘 (플랫 파일, 네트워크, RDBMS, XML 등)으로 구현 될 수 있습니다.

class YourProblematicClass { 

.... 

    public void fetchData(Object criteria) { 

      switch (this.persitanceType) { 
       case FilePersistance: 
        // open file 
        // read it 
        // find the criteria 
        // build the data 
        // close it. 
        break; 
       case NetWorkPersistance: 
        // Connect to the server 
        // Authenticate 
        // retrieve the data 
        // build the data 
        // close connection 
        break(); 
       case DataBasePersistace: 
        // Get a jdbc connection 
        // create the query 
        // execute the query 
        // fetch and build data 
        // close connection 
        break; 
      } 
      return data; 
     }  

업데이트/삭제/

public void saveData(Object data) { 

     switch (this.persitanceType) { 
      case FilePersistance: 
       // open file, go to EOF, write etc. 
       break; 
      case NetWorkPersistance: 
       // Connect to the server 
       // Authenticate 
       // etc 
       break(); 
      case DataBasePersistace: 
       // Get a jdbc connection, query, execute... 
       break; 
     } 
    } 

을 저장 동일 그리고 전 :

코드는 당신이 이것을 가지고 4 개 개의 다른 장소에서 그래서 그들 모두를 지원해야 등등 ....

public void deleteData(Object data) { 

     switch (this.persitanceType) { 
      case FilePersistance: 
       break; 
      case NetWorkPersistance: 
       break(); 
      case DataBasePersistace: 
       break; 
     } 
    } 

public void updateData(Object data) { 

     switch (this.persitanceType) { 
      case FilePersistance: 
       break; 
      case NetWorkPersistance: 
       break(); 
      case DataBasePersistace: 
       break; 
     } 
    } 
스위치/case 문을 사용하여 6,

는 문제가된다 :

  • 때마다 당신이 각 섹션에서 새로운 스위치/케이스를 삽입해야 새로운 유형을 추가하고 싶습니다.

  • 여러 번, 몇 가지 유형이 유사하며, 그들은

  • 그들이 어떤 다른 (당신이 그들을 단계적으로 수), 그리고 몇 번 그들이 당신은 할 수있다
  • 다소 차이가 다른 스위치/케이스 필요하지 않습니다 심지어 플러그인과 같은 런타임에 다른 유형을로드해야 할 필요가 있습니다.

리팩토링은 인터페이스 또는 추상 유형을 추가하고 다른 유형이 해당 인터페이스를 구현하고 해당 객체에 책임을 위임하는 것입니다. 그들의 논리에 따라 구현하는 것이

public interface PersistenceManager { 
     public void fetchData(Object criteria); 
     public void saveData(Object toSave); 
     public void deleteData(Object toDelete); 
     public void updateData(Object toUpdate); 
    } 

후 다른 구현

public class FilePersistence implements PersistanceManager { 
     public void fetchData(Object criteria) { 
        // open file 
        // read it 
        // find the criteria 
        // build the data 
        // close it. 
     } 
     public void saveData(Object toSave) { 
       // open file, go to EOF etc. 
     } 
     public void deleteData(Object toDelete){ 
      .... 
     } 
     public void updateData(Object toUpdate){ 
      .... 
     } 
    } 

그리고 다른 유형 :

그래서 당신이 뭔가를 할 것입니다. 네트워크는 소켓과 스트림을 처리 할 것이고, DB는 노드 등을 사용하여 JDBC, ResultSets 등 XML을 처리 할 것이다.

public class NetworkPersistence implements PersistanceManager { 
     public void fetchData(Object criteria) { 
      // Socket stuff 
     } 
     public void saveData(Object toSave) { 
      // Socket stuff 
     } 
     public void deleteData(Object toDelete){ 
      // Socket stuff 
     } 
     public void updateData(Object toUpdate){ 
      // Socket stuff 
     } 
    } 


    public class DataBasePersistence implements PersistanceManager { 
     public void fetchData(Object criteria) { 
      // JDBC stuff 
     } 
     public void saveData(Object toSave) { 
      // JDBC stuff 
     } 
     public void deleteData(Object toDelete){ 
      // JDBC stuff 
     } 
     public void updateData(Object toUpdate){ 
      // JDBC stuff 
     } 
    } 

마지막으로 호출을 위임 받아야합니다.

나중에

:

public YouProblematicClass { // not longer that problematic 

    PersistamceManager persistance = // initialize with the right one. 


     public void fetchData(Object criteria) { 
      // remove the switch and replace it with: 
      this.persistance.fetchData(criteria); 
     } 
     public void saveData(Object toSave) { 
      // switch removed 
      this.persistance.saveData( toSave); 
     } 
     public void deleteData(Object toDelete){ 
      this.persistance.deleteData(toDelete); 
     } 
     public void updateData(Object toUpdate){ 
      this.persistance.updateData(toUpdate); 
     } 
    } 

그래서, 당신은 단지 한 번만 유형에 따라 지속성 관리자에 대한 올바른 인스턴스를 만들어야합니다. 그런 다음 모든 호출은 다형성으로 해결됩니다. 이것이 바로 객체 지향 기술의 핵심 기능 중 하나입니다.

다른 지속성 관리자가 필요하다고 결정하면 새 구현을 만들고 클래스에 할당하면됩니다.

public WavePersistance implements PersistanceManager { 

     public void fetchData(Object criteria) { 
      // .... 
     } 
     public void saveData(Object toSave) { 
      // .... 
     } 
     public void deleteData(Object toDelete){ 
      // .... 
     } 
     public void updateData(Object toUpdate){ 
      // .... 
     } 
    } 
+2

아주 좋은 답변입니다! – mac

1

또는 1 동적 스위치 케이스의 종류를 상상할 수있다.

그 외 : 스위치 케이스, 다형성 또는 심지어 if/else를 사용하여 "노이즈"를 줄이고 코드를보다 깨끗하게 만들 수 있는지 여부를 결정하는 것이 이치에 맞다고 생각합니다. 사건의 수는 여기에서 중요한 역할을합니다.

1

내가 "클린 코드"스위치/경우에 따라 멋진 장을 가지고 대/다른 경우 같아요

0

문자열이 정적 인 경우 ENUM을 만들 수 있습니다. 스위치를 켜십시오.

1

스위치 케이스를 enum으로 바꾼 전형적인 경우를 게시합니다.

public enum PatternTypes { 

    ALPHA_CHAR, ALPHANUMERIC_CHAR, ADDITIONAL_CHAR, UNICODE_BMP_CHARS 
} 

과 기능 :

public enum PatternTypes { 

    /** 
    * RegEx patterns divided by restriction level 
    */ 
    ALPHA_CHAR("[a-zA-Z]+"), 
    ALPHANUMERIC_CHAR("[a-zA-Z0-9\\_]+"), 
    ADDITIONAL_CHAR("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"), 
    UNICODE_BMP_CHARS("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+"); 

    public String getPatternContent() { 
     return patternContent; 
    } 

    private String patternContent; 

    PatternTypes(String patternContent) { 
     this.patternContent = patternContent; 
    } 
} 

: 리팩토링 PatternTypes

private static final String ALPHA_CHAR = "[a-zA-Z]+"; 
    private static final String ALPHANUMERIC_CHAR = "[a-zA-Z0-9\\_]+"; 
    private static final String ADDITIONAL_CHAR = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"; 
    private static final String UNICODE_BMP_CHARS = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+"; 

/* 
    * Match given classAbbr with given RegEx pattern 
    */ 
    private void checkInvalidClassAbbr(String classAbbr, 
      PatternTypes classAbbrPattern) { 

     switch (classAbbrPattern) { 
     case ALPHA_CHAR: 

      checkUnmatched(classAbbr, ALPHA_CHAR, CLASS_ABBR_VAR_NAME); 
      break; 
     case ALPHANUMERIC_CHAR: 

      checkUnmatched(classAbbr, ALPHANUMERIC_CHAR, CLASS_ABBR_VAR_NAME); 
      break; 
     case ADDITIONAL_CHAR: 
      throw new MalFormedDNException("Not support Pattern Type:" 
        + classAbbrPattern); 

     case UNICODE_BMP_CHARS: 
      throw new MalFormedDNException("Not support Pattern Type:" 
        + classAbbrPattern); 
     } 

    } 

가 수정 리팩터링 전에

나는 열거 PatternTypes이 기능은 다음과 같이 단순화됩니다.

/* 
    * Match given classAbbr with given RegEx pattern 
    */ 
    private void checkInvalidClassAbbr(String classAbbr, PatternTypes classAbbrPattern) { 

      if (PatternTypes.ADDITIONAL_CHAR.equals(classAbbrPattern) || PatternTypes.UNICODE_BMP_CHARS.equals(classAbbrPattern)){ 
       throw new MalFormedDNException("RegEx pattern:" + classAbbrPattern.name() + "is not allowed for Class Abbr"); 
      } 

      checkUnmatched(classAbbr, classAbbrPattern.getPatternContent(), CLASS_ABBR_VAR_NAME); 

    } 
0

해시 맵은 메모리 사용이 불가능한 것으로 간주되므로이 용도로 열거 형을 사용할 수 있습니다.

예 :

class EnumExample4{ 
enum Season{ 
WINTER(5), SPRING(10), SUMMER(15), FALL(20); 

private int value; 
private Season(int value){ 
this.value=value; 
} 
} 
public static void main(String args[]){ 

System.out.println(Season.WINTER.value); //This gives you 5 
}} 

이 스위치 케이스를 작성 또는 진술 여부를 SVE 것입니다.

+2

클레임을 뒷받침 할 수있는 참고 자료를 몇 개 주시겠습니까? * 해시 맵은 메모리 친화적 인 것으로 간주되지 않습니다 *. 가능한 경우 답변을 수정하여 거기에 링크하십시오. – derM