스위치 문 리팩토링 그리고 스위치 문을 실제로 사용합니까?


28

기사를 읽고 궁금해했습니다. 모든 스위치 문을 Dictionary 또는 Factory로 교체하여 프로젝트에 스위치 문이 전혀 없도록 모든 스위치 문을 제거합니까?

무언가가 더해지지 않았습니다.

문제는 switch 문이 실제로 사용되거나 사전 또는 팩토리 메소드로 대체하고 있습니까? 공장 사용 ...하지만 그게 전부입니다).


10
팩토리를 구현한다고 가정하면 만들 객체 유형을 어떻게 결정합니까?
CodeART


@CodeWorks : 물론 어떤 구체적인 구현을 사용할지 결정하는 조건이 있습니다.
카니 니

@CodeWorks : 분명히 가상 생성자로. (당신이 그런 식으로 공장 패턴을 구현 할 수없는 경우, 당신은 더 나은 언어가 필요합니다.)
메이슨 윌러

답변:


44

switch진술과 다형성 모두 사용됩니다. 함수 포인터 / 람다 및 고차 함수를 지원하는 언어의 세 번째 옵션도 있습니다 : 문제의 식별자를 처리기 함수에 매핑하십시오. 이것은 예를 들어 OO 언어가 아닌 C와 *이지만 C #이지만 * (아직) OO가 아닌 *에서 사용할 수 있습니다.

일부 절차 적 언어에서 (다형성이나 고차 함수가없는) switch/ if-else문은 문제의 클래스를 해결하는 유일한 방법입니다. 이러한 사고 방식에 익숙한 많은 개발자 switch들은 다형성이 더 나은 솔루션 인 OO 언어에서도 계속 사용 했습니다. 이런 이유로 switch다형성에 유리한 진술 을 피하거나 리팩토링하는 것이 종종 권장되는 이유 입니다.

어쨌든 최상의 솔루션은 항상 대 / 소문자에 따라 다릅니다. 문제는 장기적으로 더 깔끔하고 간결하며 유지 보수가 쉬운 코드를 제공하는 옵션은 무엇입니까?

스위치 문은 종종 수십 건의 사례로 인해 다루기 어려워 져 유지 관리가 어려워 질 수 있습니다. 단일 기능으로 유지해야하므로 해당 기능이 크게 증가 할 수 있습니다. 이 경우 맵 기반 및 / 또는 다형성 솔루션으로 리팩토링을 고려해야합니다.

동일한 switch장소가 여러 곳에 나타나기 시작하면 다형성이 이러한 모든 경우를 통합하고 코드를 단순화하는 가장 좋은 방법 일 것입니다. 특히 앞으로 더 많은 사례가 추가 될 것으로 예상되는 경우; 매번 업데이트해야 할 곳이 많을수록 오류 가능성이 커집니다. 그러나 종종 개별 사례 처리기는 너무 단순하거나 너무 많거나 상호 관련되어있어 완전한 다형성 클래스 계층 구조로 리팩토링하는 것이 과도하거나 많은 중복 코드 및 / 또는 얽힘, 클래스 계층 구조를 유지하기가 어렵습니다. 이 경우 함수 / 람다를 사용하는 것이 더 간단 할 수 있습니다 (언어에서 허용하는 경우).

그러나 switch단일 장소에 간단한 경우에 몇 가지 사례 만있는 경우에는 그대로 두는 것이 가장 좋습니다.

* 여기서는 "OO"라는 용어를 느슨하게 사용합니다. "진정한"또는 "순수한"OO가 무엇인지에 대한 개념적 토론에는 관심이 없습니다.


4
+1. 또한 이러한 권장 사항은 " 다형성을 전환 하는 것을 선호합니다 "라는 단어로 표현되는 경향이 있으며이 답변과 매우 잘 어울리는 단어를 선택하는 것이 좋습니다. 책임있는 코더가 다른 선택을 할 수있는 상황이 있음을 인정합니다.
Carl Manaster

1
코드에 여러 가지가 있어도 스위치 방식을 원할 때가 있습니다. 3D 미로를 생성하는 코드를 염두에두고 있습니다. 배열의 1 바이트 셀이 클래스로 교체되면 메모리 사용이 증가합니다.
Loren Pechtel

14

이곳은 제가 공룡으로 돌아가는 곳입니다 ...

스위치 문은 그 자체로 나쁘지 않으며 문제의 문을 사용합니다.

가장 분명한 것은 나쁜 코드를 통해 반복해서 반복되는 "동일한"스위치 문입니다 (이것이 완료되면 다시 시도하지 않을 것입니다). 다형성을 사용하여. 일반적으로 중첩 된 사례에 대해서도 상당히 무섭습니다 (절대 몬스터를 사용 했었습니다. 이제 "더 나은"이 아닌 다른 방식으로 처리하는 방법을 완전히 모릅니다).

스위치로서의 사전 더 도전적인 것으로 판단됩니다. 스위치가 사례의 100 %를 다루는 경우 기본적으로 그렇습니다. 그러나 기본 사례가 있거나 조치 사례가없는 경우 좀 더 흥미로워지기 시작합니다.

반복을 피하고 올바른 위치에 객체 그래프를 작성 해야하는지에 대한 질문이라고 생각합니다.

그러나 이해 (유지 보수성) 주장도 있으며 두 가지 방법을 모두 사용합니다. 모든 작동 방식 (구현 된 패턴 및 앱)이 쉬운 방법을 이해하면 ...하지만 코드가있는 한 줄에 오면 새로운 것을 추가해야하고 추가 / 변경이 필요한 부분을 해결하기 위해 모든 곳을 뛰어 넘어야합니다.

우리의 개발 환경이 방대한 기능을 모두 갖추고 있기 때문에 종이에 인쇄 된 것처럼 코드를 이해하는 것이 바람직하다고 생각합니다. 손가락으로 코드를 따라갈 수 있습니까? 나는 실제로 아니오, 오늘날 많은 좋은 연습으로 할 수 없으며 좋은 이유가 있지만 코드로 속도를 높이는 것이 시작하기가 더 어렵다는 것을 받아들입니다.


4
나는 프로그래밍에 대해 전혀 모르는 사람 (어머니처럼)이 코드를 이해할 수 있도록 이상적인 코드를 작성해야한다고 선생님에게 말했다. 불행히도 이것은 이상적이지만 어쨌든 코드 검토에 엄마를 포함시켜야합니다!
Michael K

+1 "하지만 새로운 것을 추가해야하는 한 줄의 코드에 오면 추가 / 변경이 필요한 부분을 해결하기 위해 모든 곳을 뛰어 넘어야합니다."
quick_now

8

스위치 문 대 하위 유형 다형성은 오래된 문제이며 종종 표현 문제 에 대한 토론에서 FP 커뮤니티에서 언급됩니다 .

기본적으로 우리는 타입 (클래스)과 함수 (메소드)를 가지고 있습니다. 새로운 타입이나 새로운 메소드를 쉽게 추가 할 수 있도록 어떻게 코드를 작성 하는가?

OO 스타일로 프로그래밍하는 경우 새 메소드를 추가하기 어렵지만 (기존의 모든 클래스를 리팩토링해야 함) 이전과 동일한 메소드를 사용하는 새 클래스를 쉽게 추가 할 수 있습니다.

반면에 switch 문 (또는 OO에 해당하는 Observer 패턴)을 사용하면 새 함수를 쉽게 추가 할 수 있지만 새로운 사례 / 클래스를 추가하기는 어렵습니다.

양방향으로 확장 성이 좋은 것은 쉽지 않기 때문에 코드를 작성할 때, 어느 방향으로 확장 할 것인지에 따라 다형성 또는 스위치 명령문을 사용할지 결정하십시오.


4
프로젝트에 스위치 명령문이 전혀 없도록 사전 또는 팩토리로 바꾸어 모든 스위치 명령문을 제거합니까?

아닙니다. 그러한 절대적인 것은 좋은 생각이 아닙니다.

많은 곳에서 사전 / 조회 / 공장 / 다형성 디스패치는 switch 문보다 더 나은 디자인을 제공하지만 여전히 사전을 채워야합니다. 어떤 경우에는 실제로 진행중인 작업을 모호하게하고 단순히 switch 문을 인라인으로 작성하는 것이 더 읽기 쉽고 유지 관리가 용이합니다.


그리고 팩토리와 딕셔너리와 룩업을 언 롤링하면 기본적으로 switch 문으로 나타납니다. array [hash (search)]이면 array [hash (search)]를 호출합니다. 컴파일 된 스위치가 아닌 런타임 확장 가능하지만.
Zan Lynx

@ ZanLynx, 적어도 C #에서는 완전한 반대입니다. 사소하지 않은 switch 문에 대해 생성 된 IL을 보면 컴파일러가 더 빠르기 때문에이를 사전으로 바꾼다는 것을 알 수 있습니다.
David Arno

@DavidArno : "완전한 반대"? 내가 읽는 방식은 정확히 똑 같았습니다. 어떻게 반대가 될 수 있습니까?
Zan Lynx

2

이것이 언어에 구애받지 않는 폴 스루 코드 인 방식으로 보면 다음과 같은 switch문장에 가장 효과적입니다 .

switch(something) {
   case 1:
      foo();
   case 2:
      bar();
      baz();
      break;

   case 3:
      bang();
   default:
      bizzap();
      break;
}

매우 어색한 기본 경우 if와 동일합니다 . 그리고 추락이 많을수록 조건 목록이 길어질 수 있습니다.

if (1 == something) {
   foo();
}
if (1 == something || 2 == something) {
   bar();
   baz();
}
if (3 == something) {
   bang();
}
if (1 != something && 2 != something) {
   bizzap();
}

(그러나 다른 답변 중 일부에 따르면 질문의 요점을 놓친 것 같습니다 ...)


저는 추락 진술의 사용을와 switch같은 수준으로 간주합니다 goto. 수행 할 알고리즘에 구조화 된 프로그래밍 구조에 맞는 제어 흐름이 필요한 경우 이러한 구조를 사용해야하지만 알고리즘이 이러한 구조에 적합하지 않으면 goto다른 제어 구조에 맞는 플래그 또는 다른 제어 논리를 추가하는 것보다 낫습니다. .
supercat

1

대소 문자 구분에 따른 스위치 문은 실제로 사용됩니다. 함수형 프로그래밍 언어는 패턴 일치라는 것을 사용하여 입력에 따라 기능을 다르게 정의 할 수 있습니다. 그러나 객체 지향 언어에서는 다형성을 사용하여 동일한 목표에보다 우아하게 도달 할 수 있습니다. 단순히 메소드를 호출하면 객체의 실제 유형에 따라 해당 메소드의 구현이 실행됩니다. 이것이 스위치 문이 코드 냄새라는 아이디어의 이유입니다. 그러나 OO 언어에서도 추상 팩토리 패턴을 구현하는 데 유용 할 수 있습니다.

tl; dr-유용하지만 꽤 자주 더 잘할 수 있습니다.


2
나는 거기에 약간의 편견이 있습니다-왜 다형성이 패턴 매칭보다 더 우아합니까? 그리고 FP에 다형성이 존재하지 않는다고 생각하는 이유는 무엇입니까?
tdammers

@tdammers 우선 나는 다형성이 FP에 존재하지 않는다는 것을 의미하지는 않았다. Haskell은 애드혹 및 파라 메트릭 다형성을 지원합니다. 패턴 일치는 대수 데이터 유형에 적합합니다. 그러나 외부 모듈의 경우 노출 생성자가 필요합니다. 분명히 이것은 추상 데이터 유형 (대수 데이터 유형으로 실현)의 캡슐화를 깨뜨립니다. 그렇기 때문에 다형성이 더 우아하다고 생각합니다 (FP에서도 가능).
scarfridge

타입 클래스와 인스턴스를 통해 다형성을 잊고 있습니다.
tdammers

당신은 표현 문제에 대해 들어 본 적이 있습니까? OO와 FP는 당신이 그것에 대해 생각하지 않으면 다른 상황에서 더 좋습니다.
hugomg

@tdammers Ad hoc 다형성을 언급했을 때 어떤 종류의 다형성을 생각하십니까? 임시 다형성은 유형 클래스를 통해 Haskell에서 실현됩니다. 내가 잊었다 고 어떻게 말할 수 있습니까? 사실이 아닙니다.
scarfridge
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.