부울 매개 변수를 사용하여 값을 결정하는 것은 잘못입니까?


39

에 따르면 이 동작을 결정하는 부울 매개 변수를 사용하는 것이 잘못인가? 부울 매개 변수를 사용하여 동작을 결정하지 않는 것이 중요하다는 것을 알고 있습니다.

원본 버전

public void setState(boolean flag){
    if(flag){
        a();
    }else{
        b();
    }
    c();
}

새로운 버전:

public void setStateTrue(){
    a();
    c();
}

public void setStateFalse(){
    b();
    c();
}

그러나 부울 매개 변수가 동작 대신 값을 결정하는 데 사용되는 경우는 어떻습니까? 예 :

public void setHint(boolean isHintOn){
    this.layer1.visible=isHintOn;
    this.layer2.visible=!isHintOn;
    this.layer3.visible=isHintOn;
}

isHintOn 플래그를 제거하고 두 가지 별도의 함수를 만들려고합니다.

public void setHintOn(){
    this.layer1.visible=true;
    this.layer2.visible=false;
    this.layer3.visible=true;
}

public void setHintOff(){
    this.layer1.visible=false;
    this.layer2.visible=true;
    this.layer3.visible=false;
}

그러나 수정 된 버전은 다음과 같은 이유로 유지 관리가 쉽지 않습니다.

  1. 원래 버전보다 더 많은 코드가 있습니다.

  2. layer2의 가시성이 힌트 옵션과 반대임을 명확하게 보여줄 수는 없습니다.

  3. 새 레이어 (예 : layer4)가 추가되면 추가해야합니다

    this.layer4.visible=false;
    

    this.layer4.visible=true;  
    

    setHintOn () 및 setHintOff ()에 별도로

따라서 내 질문은 부울 매개 변수를 사용하여 값을 결정하는 데만 동작이 아닌 경우 (예 : 해당 매개 변수에 if-else가 아닌 경우) 해당 부울 매개 변수를 제거하는 것이 여전히 권장됩니까?


26
결과 코드가 더 읽기 쉽고 유지 관리 가능하다면 결코 잘못이 아닙니다. ;-) 두 개의 별도 메서드 대신 단일 메서드를 사용하는 것이 좋습니다.
helb

32
이러한 부울을 설정하는 메소드의 단일 구현으로 클래스를보다 쉽게 ​​유지 보수하고 구현에 대한 이해를 얻을 수 있다는 강력한 주장을 제시합니다. 아주 잘; 그것들은 합법적 인 고려 사항입니다. 그러나 클래스 의 공용 인터페이스는이를 수용하기 위해 변형 될 필요가 없습니다. 별도의 방법을 이해하고 작업 할 공용 인터페이스를 쉽게 만들 것입니다 경우를 정의 setHint(boolean isHintOn)A와 개인 방법, 공공 추가 setHintOn하고 setHintOff각각 호출 방법 setHint(true)setHint(false).
Mark Amery 12

9
나는 그 메소드 이름에 매우 만족하지 않을 것입니다 : 그들은 실제로 어떤 이점도 제공하지 않습니다 setHint(true|false). 감자 포타 토. 적어도 setHintand 같은 것을 사용하십시오 unsetHint.
Konrad Rudolph


4
@kevincline 조건이 하나의 이름이면 is처음에 씁니다 . isValid그렇다면 왜 두 단어로 바꾸어야합니까? 게다가, "보다 자연스러운"은 보는 사람의 눈에 있습니다. 영어 문장으로 발음하고 싶다면, "힌트"가 들어간 "힌트가있는 경우"를 갖는 것이 더 자연 스러울 것입니다.
Mr Lister

답변:


95

API 디자인은 호출 측 에서 API 클라이언트에게 가장 유용한 것에 중점을 두어야합니다 .

예를 들어,이 새로운 API가 호출자에게 다음과 같이 정기적으로 코드를 작성해야하는 경우

if(flag)
    foo.setStateTrue();
else
    foo.setStateFalse();

그러면 매개 변수를 피하는 것이 호출자가 쓸 수있는 API를 갖는 것보다 나쁘다는 것이 분명해야합니다.

 foo.setState(flag);

이전 버전에서는 문제가 발생하여 호출 측에서 해결해야합니다 (아마도 두 번 이상). 가독성이나 유지 관리 성이 향상되지는 않습니다.

그러나 구현 측면 에서는 퍼블릭 API의 모양을 지시해서는 안됩니다. 같은 함수 경우 setHint매개 변수와 구현에 적은 코드를 필요로하지만 측면에서 API가 setHintOn/ setHintOff클라이언트에 사용할 쉽게 보이는, 하나는이 방법을 구현할 수 있습니다 :

private void setHint(boolean isHintOn){
    this.layer1.visible=isHintOn;
    this.layer2.visible=!isHintOn;
    this.layer3.visible=isHintOn;
}

public void setHintOn(){
   setHint(true);
}

public void setHintOff(){
   setHint(false);
}

따라서 공개 API에는 부울 매개 변수가 없지만 여기에는 중복 논리가 없으므로 새로운 요구 사항 (예 : 질문 예)이 도착하면 변경해야 할 곳은 한 곳뿐입니다.

이것은 다른 방식으로도 작동합니다. setState위 의 방법이 두 개의 다른 코드 조각 사이를 전환 해야하는 경우 해당 코드 조각을 두 개의 다른 개인 메서드로 리팩토링 할 수 있습니다. 따라서 IMHO는 내부를 살펴보면서 "하나의 매개 변수 / 하나의 방법"과 "제로 매개 변수 / 두 개의 방법"중 하나를 결정하기위한 기준을 검색하는 것은 의미가 없습니다. 그러나 API의 소비자 역할에서 API를 보려는 방식을 살펴보십시오.

확실하지 않은 경우 "테스트 중심 개발"(TDD)을 사용해보십시오. 그러면 공용 API 및 사용 방법에 대해 생각하게됩니다.


DocBrown, 적절한 구분선은 각 상태의 설정이 복잡하고 돌이킬 수없는 부작용인지 여부입니다. 예를 들어, 주석에 표시되는 내용을 수행하는 플래그를 토글하고 기본 상태 시스템이없는 경우 다른 상태를 매개 변수화합니다. 예를 들어, SetLoanFacility(bool enabled)대출을 제공 한 후에는 다시 가져 오기가 쉽지 않고 두 옵션에 완전히 다른 논리가 포함될 수 있으므로 별도의 Create로 이동하고 싶기 때문에과 같은 방법을 매개 변수화 하지 않습니다. / 메소드 제거.
Steve

15
@Steve : 여전히 구현 측면에서 보는 요구 사항에서 API를 설계하려고합니다. 똑바로 : 그것은 전혀 관련이 없습니다. 호출 측에서 사용하기 쉬운 공용 API 변형을 사용하십시오. 내부적으로 항상 두 개의 공개 메소드가 매개 변수를 사용하여 하나의 개인을 호출하게 할 수 있습니다. 또는 매개 변수를 사용하여 하나의 메소드가 다른 논리를 사용하는 두 개의 개인 메소드간에 전환 할 수 있습니다.
Doc Brown

@Steve : 내 편집 내용을 참조하십시오.
Doc Brown

나는 당신의 모든 요점을 취합니다-나는 실제로 발신자의 입장에서 생각하고 (따라서 "주석에 말하는 것"에 대한 나의 언급) 발신자가 일반적으로 각 접근법을 사용할 것으로 예상되는 적절한 규칙을 수립하려고합니다. 규칙은 호출자가 반복 호출이 dem 등원을 기대하는지 여부와 상태 전이가 제한되지 않고 복잡한 부작용이 없는지 여부입니다. 실내 조명 스위치를 켜고 끄는 기능은 매개 변수화되며 지역 발전소를 켜고 끄는 방법은 다중 방법입니다.
Steve

1
@Steve 따라서 사용자가 특정 설정을 확인해야하는 경우 Toggle()제공하는 올바른 기능이 아닙니다. 그게 요점입니다. 발신자가 "변경 내용"만 신경 쓰고 "결국 결과"가 아니라면 Toggle()추가 확인 및 의사 결정을 피하는 옵션입니다. 나는 그것을 COMMON 케이스라고 부르지 않을 것이며, 정당한 이유없이 사용할 수 있도록 권장하지는 않지만 사용자가 토글이 필요하면 토글을 줄 것입니다.
Kamil Drakari

40

Martin Fowler는 켄트 벡 (Kent Beck)이 별도의 setOn() setOff()방법추천 한다고 인용 했지만, 이것이 불가침으로 간주되어서는 안된다고 말합니다.

UI 컨트롤이나 데이터 소스와 같은 부울 소스에서 [sic] 데이터를 가져 오는 setSwitch(aValue)경우

if (aValue)
  setOn();
else
  setOff();

이것은 호출자가보다 쉽게 ​​사용할 수 있도록 API를 작성해야하는 예이므로 호출자가 어디에서 왔는지 알면 해당 정보를 염두에두고 API를 설계해야합니다. 이것은 또한 발신자를 두 가지 방법으로 모두 얻는 경우 때때로 두 가지 스타일을 모두 제공 할 수 있다고 주장합니다.

또 다른 추천하는 열거 값 또는 플래그를 입력 사용할truefalse더 나은 상황에 특정 이름. 당신의 예에서, showHint그리고 hideHint더 나은 수 있습니다.


16
내 경험상 setSwitch (value)는 대답에 인용 된 if / else 코드로 인해 setOn / setOff보다 전체 코드가 거의 항상 거의 없습니다. 나는 setSwitch (value) 대신 setOn / setOff API를 제공하는 개발자를 저주하는 경향이 있습니다.
26 개

1
비슷한 렌즈로 살펴보기 : 값을 하드 코딩해야하는 경우 어느 쪽이든 사용하기 쉽습니다. 그러나 사용자 입력으로 설정 해야하는 경우 값을 직접 전달할 수 있으면 단계가 저장됩니다.
Nic Hartley

@ 17of26은 구체적인 반례로 (Apple의 AppKit에는 뷰가 다시 그려야하고 그렇지 않아야하는 경우 -[NSView setNeedsDisplay:]전달 하는 방법이 있습니다 .) 거의 말하지 않아도되므로 UIKit 에는 매개 변수가 없습니다. 해당 방법 이 없습니다 . YESNO-[UIView setNeedsDisplay]-setDoesNotNeedDisplay
Graham Lee

2
@GrahamLee, Fowler의 주장은 매우 미묘하며 실제로 판단에 달려 있다고 생각합니다. 나는 bool isPremium그의 예제에서 플래그를 사용하지 않을 것이지만 BookingType bookingType, 각 예약의 논리가 상당히 다르지 않은 한 enum ( )을 사용 하여 동일한 방법을 매개 변수화 할 것입니다. Fowler가 참조하는 "얽힌 논리"는 종종 두 모드의 차이점이 무엇인지 알고 자하는 경우에 바람직합니다. 그리고 그것들이 근본적으로 다르면 매개 변수가있는 방법을 외부에 노출시키고 별도의 방법을 내부적으로 구현합니다.
Steve

3

귀하의 게시물에 API와 구현의 두 가지를 혼합한다고 생각합니다. 두 경우 모두 항상 사용할 수있는 강력한 규칙은 없다고 생각하지만이 두 가지를 독립적으로 (가능한 한) 고려해야합니다.

API로 시작해 봅시다.

public void setHint(boolean isHintOn)

과:

public void setHintOn()
public void setHintOff()

객체가 제공하는 대상과 클라이언트가 API를 사용하는 방법에 따라 유효한 대안입니다. Doc이 지적했듯이 사용자가 UI 컨트롤, 사용자 작업, 외부, API 등의 부울 변수를 이미 가지고 있다면 첫 번째 옵션이 더 의미가 있습니다. 그렇지 않으면 클라이언트 코드에 여분의 if 문을 강요합니다 . 그러나 예를 들어 프로세스를 시작할 때 힌트를 true로 변경하고 마지막에 false를 변경하면 첫 번째 옵션은 다음과 같습니다.

setHint(true)
// Do your process
…
setHint(false)

두 번째 옵션은 당신에게 이것을 제공합니다 :

setHintOn()
// Do your process
…
setHintOff()

어떤 IMO가 훨씬 읽기 쉽기 때문에이 경우 두 번째 옵션을 사용합니다. 분명히, 두 옵션을 모두 제공하는 것을 막을 수있는 것은 없습니다 (또는 그 이상으로 Graham이 말한 것처럼 열거 형을 사용할 수 있습니다).

요점은 객체가 수행해야 할 작업과 구현 방법이 아니라 클라이언트가 어떻게 사용하는지에 따라 API를 선택해야한다는 것입니다.

그런 다음 공개 API를 구현하는 방법을 선택해야합니다. 메소드 setHintOnsetHintOff공개 API를 선택했으며 예제와 같이이 공통 논리를 공유 한다고 가정 해 보겠습니다 . 개인 메소드 (doc에서 복사 한 코드)를 통해이 논리를 쉽게 추상화 할 수 있습니다.

private void setHint(boolean isHintOn){
    this.layer1.visible=isHintOn;
    this.layer2.visible=!isHintOn;
    this.layer3.visible=isHintOn;
}

public void setHintOn(){
   setHint(true);
}

public void setHintOff(){
   setHint(false);
}

반대로, setHint(boolean isHintOn)우리가 API를 선택했지만 힌트를 On으로 설정하는 이유는 API를 Off로 설정하는 것과 완전히 다른 이유 때문에 예제를 뒤집어 봅시다. 이 경우 다음과 같이 구현할 수 있습니다.

public void setHint(boolean isHintOn){
    if(isHintOn){
        // Set it On
    } else {
        // Set it Off
    }    
}

또는:

public void setHint(boolean isHintOn){    
    if(isHintOn){
        setHintOn()
    } else {
        setHintOff()
   }    
}

private void setHintOn(){
   // Set it On
}

private void setHintOff(){
   // Set it Off 
}

요점은 두 경우 모두 먼저 퍼블릭 API를 선택한 다음 구현이 다른 방식이 아니라 선택한 API (및 제약 조건)에 맞게 조정되었다는 것입니다.

그런데, 나는 같은 당신이 행동을 결정하는 부울 매개 변수를 사용하는 방법에 대한 링크 된 게시물에 적용 생각 당신이 특정 유스 케이스가 아닌 특정 경우에 비록 일부 하드 규칙 (에 따라 결정해야한다, 즉 일반적으로 할 수있는 올바른 일 여러 기능에서 중단됩니다).


3
보조 노트로, 의사 블록 (끝의 시작 부분에 하나의 명령문, 하나)와 같은 그것의 무언가가, 당신은 아마 사용해야하는 경우 beginend또는 동의어, 그냥 명시 적으로는 그들이 무엇을 명확하게하고,하는 것을 의미하는 시작에는 결말이 있어야하고 그 반대도 마찬가지입니다.
Nic Hartley

Nic에 동의하고 추가 할 것입니다 : 시작과 끝이 항상 결합되도록하려면 언어 별 관용구도 제공해야합니다 .C ++의 RAII / scope guard, usingC #의 블록, withPython의 명령문 컨텍스트 관리자, 전달 람다 또는 호출 가능한 객체 (예 : Ruby 블록 구문) 등의
본문

나는 두 가지 점에 동의하며, 다른 경우를 설명하기 위해 간단한 예를 제시하려고했습니다 (두 가지 모두 지적한 것처럼 나쁜 예입니다).
jesm00

2

가장 먼저해야 할 일 : 코드는 약간 길기 때문에 자동으로 유지 관리하기가 쉽지 않습니다. 선명도가 중요합니다.

자, 만약 당신이 정말로 데이터를 다루고 있다면, 당신이 가진 것은 부울 속성에 대한 세터입니다. 이 경우 해당 값을 직접 저장하고 레이어 가시성, 즉

bool isBackgroundVisible() {
    return isHintVisible;
}    

bool isContentVisible() {
    return !isHintVisible;
}

(저는 레이어에 실제 이름을 부여 할 자유를 얻었습니다. 원래 코드에이 이름이 없으면 시작하겠습니다.)

이것은 여전히 setHintVisibility(bool)방법 이 있는지에 대한 질문으로 당신을 떠납니다 . 개인적으로 나는 그것을 showHint()and hideHint()메소드로 바꾸는 것이 좋습니다. 두 가지 모두 실제로 간단하며 레이어를 추가 할 때 변경하지 않아도됩니다. 그러나 옳고 그름은 분명하지 않습니다.

이제 함수를 호출하면 실제로 해당 레이어의 가시성이 변경되면 실제로 동작이있는 것입니다. 이 경우 별도의 방법을 권장합니다.


tl; dr is : 레이어를 추가 할 때 변경할 필요가 없으므로 두 기능으로 분할하는 것이 좋습니다. layer4가 추가되면 "this.layer4.visibility = isHintOn"이라고 말해야하므로 동의하지 않습니다. 레이어가 추가 될 때 하나의 함수가 아닌 두 개의 함수를 편집해야합니다.
Erdrik Ironrose

아니요 (명확하게 ) 명확성을 위해 권장하지 않습니다 ( showHintvs setHintVisibility). OP가 걱정했기 때문에 새로운 레이어를 언급했습니다. 또한 새로운 메소드 하나만 추가하면 isLayer4Visible됩니다. showHint그리고 hideHint바로 설정 isHintVisible참 / 거짓에 속성을 그 변경되지 않습니다.
doubleYou

1
@doubleYou, 더 긴 코드는 자동으로 유지 관리하기가 쉽지 않다고 말합니다. 코드 길이는 유지 관리 및 명확성 의 주요 변수 중 하나이며 구조적 복잡성만으로도 극복 될 수 있다고 말하고 싶습니다 . 더 길고 구조적으로 복잡한 코드는 그럴 가치가있다. 그렇지 않으면 간단한 문제는 코드보다 더 복잡한 처리를받을 수 있고, 코드베이스는 불필요한 라인 ( "너무 많은 간접 수준"문제)의 덤을 얻는다.
Steve

@Steve 본인은 오버 엔지니어링 할 수 있다는 것에 완전히 동의합니다. 즉, 코드를 더 명확하게 만들지 않고 코드를 더 길게 만들 수 있습니다.
doubleYou

이러한 코드를 복용하고 더 라인을 다시 작성 - "코드 골프"생각 @ 스티브 않는 보통 명확하게합니다. “코드 골프”는 극단적이지만 모든 것을 하나의 영리한 표현으로 만드는 것은“우아한”것으로 생각하는 컴파일러가 여전히 많으며 컴파일러가 충분히 최적화하지 못했기 때문에 더 빠를 수도 있습니다.
BlackJack

1

두 번째 예에서는 부울 매개 변수가 적합합니다. 이미 알고 있듯이 부울 매개 변수 자체에는 문제가 없습니다. 플래그를 기반으로 동작을 전환하는 데 문제가 있습니다.

첫 번째 예제는 이름 지정이 setter 메소드를 나타 내기 때문에 문제가 있지만 구현 방식이 다른 것 같습니다. 그래서 당신은 행동을 바꾸는 반 패턴 잘못 명명 된 방법을 가지고 있습니다. 그러나 메소드가 실제로 규칙적인 setter라면 (동작 전환이없는 경우)에는 아무런 문제가 없습니다 setState(boolean). 두 가지 방법을 갖는, setStateTrue()그리고 setStateFalse()단지 쓸데없는 이익을 위해 일을 복잡하게한다.


1

이 문제를 해결하는 또 다른 방법은 각 힌트를 나타내는 객체를 도입하고 해당 힌트와 관련된 부울 값을 결정하도록 객체를 책임지게하는 것입니다. 이렇게하면 단순히 두 개의 부울 상태가 아닌 새로운 순열을 추가 할 수 있습니다.

예를 들어 Java에서는 다음을 수행 할 수 있습니다.

public enum HintState {
    SHOW_HINT(true, false, true),
    HIDE_HINT(false, true, false);

    private HintState(boolean layer1Visible, boolean layer2Visible, boolean layer3Visible) {
         // constructor body and accessors omitted for clarity
    }
}

그러면 발신자 코드는 다음과 같습니다.

setHint(HintState.SHOW_HINT);

구현 코드는 다음과 같습니다.

public void setHint(HintState hint) {
    this.layer1Visible = hint.isLayer1Visible();
    this.layer2Visible = hint.isLayer2Visible();
    this.layer3Visible = hint.isLayer3Visible();
}

이렇게하면 강력한 형식의 명명 된 의도 를 해당 상태 집합에 명확하게 매핑하는 새 데이터 형식을 정의하는 대신 구현 코드와 호출자 코드를 간결하게 유지할 수 있습니다. 나는 그것이 모든 것이 더 낫다고 생각합니다.


0

따라서 내 질문은 부울 매개 변수를 사용하여 값을 결정하는 데만 동작이 아닌 경우 (예 : 해당 매개 변수에 if-else가 아닌 경우) 해당 부울 매개 변수를 제거하는 것이 여전히 권장됩니까?

그런 것들에 대해 의문이 생길 때 스택 추적이 어떻게 보이는지 그림으로보고 싶습니다.

몇 년 동안 나는 settergetter 와 동일한 기능을 사용하는 PHP 프로젝트에서 일했습니다 . null 을 전달 하면 값을 반환하고 그렇지 않으면 설정합니다. 작업하는 것이 끔찍했습니다 .

스택 추적의 예는 다음과 같습니다.

function visible() : line 440
function parent() : line 398
function mode() : line 384
function run() : line 5

내부 상태 에 대해 전혀 몰랐 으며 디버깅이 더 어려워졌습니다. 다른 부작용이 많이 있지만 자세한 함수 이름에 이 있고 함수가 단일 동작을 수행 할 때 명확성 을 확인하십시오 .

이제 부울 값을 기반으로 A 또는 B 동작이있는 함수의 스택 추적 작업에 대해 설명합니다.

function bar() : line 92
function setVisible() : line 120
function foo() : line 492
function setVisible() : line 120
function run() : line 5

당신이 나에게 묻는다면 혼란 스럽습니다. 동일한 setVisible라인은 두 개의 다른 추적 경로를 생성합니다.

다시 질문으로 돌아가십시오. 스택 추적이 어떻게 보이는지, 어떻게 발생 하는지를 사람들에게 전달하는 방법을 파악하고 미래의 사람이 코드를 디버깅하도록 도와 주는지 스스로에게 물어보십시오.

다음은 몇 가지 팁입니다.

  • 인수 값을 알 필요없이 의도를 암시하는 명확한 함수 이름
  • 함수는 단일 작업을 수행
  • 이름은 돌연변이 또는 불변 행동을 의미합니다
  • 언어 및 도구의 디버깅 능력과 관련된 디버깅 문제를 해결합니다.

때로는 현미경에서 코드가 과도하게 보이지만 더 큰 그림으로 다시 가져 가면 최소한의 접근 방식으로 코드가 사라집니다. 당신이 그것을 유지할 수 있도록 눈에 띄는 데 필요한 경우. 많은 작은 기능을 추가하면 지나치게 장황하게 느껴질 수 있지만 더 큰 상황에서 광범위하게 사용하면 유지 관리 성이 향상됩니다.


1
setVisible스택 추적 에 대해 혼란스러워하는 것은 호출하면 호출 setVisible(true)이 발생 하는 것으로 보입니다 setVisible(false)(또는 추적이 발생하는 방식에 따라 다른 방법으로).
David K

0

무언가의 동작을 변경하기 boolean위해 플래그 로 메소드에 매개 변수를 메소드에 전달하는 거의 모든 경우에이를 위해보다 명확 하고 유형이 안전한 방법을 고려해야합니다 .

Enum상태를 나타내는 것만 사용하면 코드의 이해력이 향상됩니다.

이 예제는 다음 Node클래스를 사용합니다 JavaFX.

public enum Visiblity
{
    SHOW, HIDE

    public boolean toggleVisibility(@Nonnull final Node node) {
        node.setVisible(!node.isVisible());
    }
}

많은 JavaFX객체 에서 발견되는 것보다 항상 낫습니다 .

public void setVisiblity(final boolean flag);

그러나 나는 생각 .setVisible()하고 .setHidden()하여 상황에 가장 적합한 솔루션입니다 플래그 A는 boolean그 이상 자세한 가장 명시 적 및 때문이다.

여러 선택 항목이있는 경우이 방법을 사용하는 것이 더 중요합니다. EnumSet이런 이유로 존재합니다.

Ed Mann은이 주제에 대해 정말 좋은 블로그 게시물을 가지고 있습니다. 나는 그가 말한 것을 역설하려고 했으므로 노력을 반복하지 않기 위해이 답변에 대한 부록으로 블로그 게시물에 대한 링크를 게시 할 것입니다.


0

(부울) 매개 변수를 전달하는 일부 인터페이스에 대한 접근 방식과 해당 매개 변수가없는 오버로드 된 방법 사이를 결정할 때 소비하는 클라이언트를 찾으십시오.

모든 사용량이 상수 값을 전달하면 (예 : true, false) 과부하를 주장합니다.

모든 사용법이 변수 값을 전달하면 매개 변수 접근 방식을 사용하는 메소드가 필요합니다.

두 가지 중 어느 것도 적용되지 않으면 클라이언트 사용이 혼합되어 있음을 의미하므로 두 가지 형식을 모두 지원할 것인지 또는 한 범주의 클라이언트를 다른 범주 (보다 부 자연스러운 스타일)에 맞출 것인지 선택해야합니다.


만약에 당신이 통합 된 시스템을 설계하고 당신은 있는 궁극적으로 코드 생산자와 코드의 "사용자 클라이언트"모두? 소비하는 고객의 입장에서 서있는 사람은 어떻게 다른 방법에 대한 접근 방식을 선호해야합니까?
Steve

@Steve, 소비 클라이언트로서 상수 또는 변수를 전달하는지 여부를 알고 있습니다. 상수를 전달하는 경우 매개 변수없이 과부하를 선호하십시오.
Erik Eidt

그러나 나는 그것이 왜 그런지를 분명히하는 데 관심이 있습니다. 제한된 수의 상수에 열거 형을 사용하지 않는 이유는 무엇입니까?이 유형의 목적을 위해 정확하게 설계된 대부분의 언어에서 가벼운 구문이기 때문입니까?
Steve

@Steve, 디자인 타임 / 컴파일 타임에 클라이언트가 모든 경우에 상수 값 (true / false)을 사용한다는 것을 알고 있다면 하나의 일반화 된 메소드 (매개 변수를 취하는) 대신 실제로 두 가지 다른 특정 메소드가 있음을 제안합니다. 매개 변수화 된 메소드가 사용되지 않을 때 일반화를 도입하는 것에 반대한다고 주장합니다 .YAGNI 인수입니다.
Erik Eidt

0

설계시 고려해야 할 두 가지 사항이 있습니다.

  • API : 사용자에게 제공하는 인터페이스,
  • 구현 : 명확성, 유지 보수성 등

그들은 둥글게되어서는 안됩니다.

다음과 같이 완벽하게 괜찮습니다.

  • API에 여러 개의 메소드를 단일 구현으로 위임
  • 조건에 따라 여러 구현으로 API 디스패치에 단일 메소드가 있습니다.

따라서 구현 설계의 비용 / 이점에 의해 API 설계의 비용 / 이점의 균형을 맞추려는 주장은 모호하며 신중하게 검토해야합니다.


API 측면에서

프로그래머는 일반적으로 프로그래밍 가능한 API를 선호합니다. 호출 할 함수를 결정하기 위해 값에 if/ switch문이 필요할 때보 다 값을 전달할 때 코드가 훨씬 명확 합니다.

후자는 각 함수가 다른 인수를 기대하는 경우 필요할 수 있습니다.

따라서 귀하의 경우에는 단일 방법 setState(type value)이 더 좋습니다.

그러나 , 무명보다 나쁜 건 없다 true, false, 2, 등 ... 그 마법의 값은 자신에 아무런 의미가 없습니다. 원시적 인 집착을 피하고 강한 타이핑을 받아들이십시오.

따라서 API POV에서 다음을 원합니다 setState(State state).


구현 측면에서

더 쉬운 일을하는 것이 좋습니다.

방법이 단순하면 함께 유지하는 것이 가장 좋습니다. 제어 흐름이 복잡하면 여러 가지 방법으로 구분하는 것이 가장 좋습니다. 각 방법은 파이프 라인의 하위 사례 또는 단계를 처리합니다.


마지막으로 그룹화를 고려하십시오 .

귀하의 예 (가독성을 위해 공백이 추가됨) :

this.layer1.visible = isHintOn;
this.layer2.visible = ! isHintOn;
this.layer3.visible = isHintOn;

layer2트렌드를 버리고 있습니까? 기능입니까, 아니면 버그입니까?

이 목록을 가질 수있을 수 [layer1, layer3][layer2],로 명시 가 함께 그룹화하는 이유를 나타내는 이름을 입력 한 다음 해당 목록을 반복.

예를 들면 다음과 같습니다.

for (auto layer : this.mainLayers) { // layer2
    layer.visible = ! isHintOn;
}
for (auto layer : this.hintLayers) { // layer1 and layer3
    layer.visible = isHintOn;
}

이 코드는 스스로를 말하지만 두 그룹이 있고 그 행동이 다른지 분명 합니다.


0

setOn() + setOff()vs set(flag)질문과 별도로 부울 유형이 최선인지 여부를 신중하게 고려합니다. 세 번째 옵션이 절대 없을까요?

부울 대신 열거 형을 고려하는 것이 좋습니다. 확장 성을 허용 할뿐 아니라 부울을 잘못된 방식으로 가져 오기가 더 어려워집니다. 예 :

setHint(false)

vs

setHint(Visibility::HIDE)

열거 형을 사용하면 누군가가 '필요한 경우'옵션을 원할 때 확장하는 것이 훨씬 쉽습니다.

enum class Visibility {
  SHOW,
  HIDE,
  IF_NEEDED // New
}

vs

setHint(false)
setHint(true)
setHintAutomaticMode(true) // New

0

...에 따르면, 부울 매개 변수를 사용하여 동작을 결정하지 않는 것이 중요하다는 것을 알고 있습니다.

이 지식을 다시 평가 해 보시기 바랍니다.

우선, 나는 당신이 당신이 연결 한 SE 질문에 당신이 제안하고 있다는 결론을 보지 못했습니다. 그들은 주로 여러 단계의 메소드 호출을 통해 매개 변수를 전달하는 것에 대해 이야기하고 있습니다.

귀하의 예에서는 분석법에서 바로 매개 변수를 평가하고 있습니다. 그런 점에서 다른 종류의 매개 변수와 전혀 다르지 않습니다.

일반적으로 부울 매개 변수를 사용하는 데 아무런 문제가 없습니다. 그리고 분명히 어떤 매개 변수가 행동을 결정합니까, 아니면 왜 처음에 그것을 가질 것입니까?


0

질문 정의

제목 질문은 "[...]에 잘못입니까?"입니다. - "잘못"이 무슨 뜻이야?

C # 또는 Java 컴파일러에 따르면 잘못된 것이 아닙니다. 나는 당신이 그것을 알고 있고 그것이 당신이 요구하는 것이 아닙니다. 그 외에는 n프로그래머가 n+1다른 의견을 가지고 있습니다. 이 답변 은 Clean Code 책에서 이에 대해 말한 내용을 나타냅니다.

대답

Clean Code 는 일반적으로 함수 인수에 대해 강력한 예를 만듭니다.

인수는 어렵다. 그들은 많은 개념적 힘을 취합니다. [...] 독자들은 그것을 볼 때마다 해석해야했습니다.

여기서 "독자"는 API 소비자 일 수 있습니다. 또한이 코드가 무엇을하는지 모르는 다음 코더 일 수도 있습니다. 그들은 한 번 유지 하고 한 번 염두에 가지 기능을 개별적 으로 거치거나 한 가지 기능을 두 번 거치게 됩니다. 요컨대, 가능한 적은 인수를 사용하십시오 .truefalse

플래그 인수의 구체적인 경우는 나중에 직접 해결됩니다.

플래그 인수는 추악합니다. 부울을 함수에 전달하는 것은 정말 끔찍한 연습입니다. 이 함수는 메소드의 서명을 즉시 복잡하게하여이 함수가 둘 이상의 기능을 수행한다고 큰 소리로 선포합니다. 플래그가 true 인 경우, 플래그가 false 인 경우 다른 작업을 수행합니다!

Clean Code에 따르면 질문에 직접 대답하려면 해당 매개 변수를 제거하는 것이 좋습니다.


추가 정보:

예제는 다소 단순하지만 코드에서도 간단하게 전파되는 것을 볼 수 있습니다. 매개 변수 없음 함수는 간단한 대입 만 수행하는 반면 다른 함수는 동일한 목표에 도달하기 위해 부울 연산을 수행해야합니다. 이 간단한 예제에서는 사소한 부울 산술이지만 실제 상황에서는 매우 복잡 할 수 있습니다.


여기에서는 API 사용자에 의존해야한다는 많은 주장을 보았습니다. 많은 곳 에서이 작업을 수행하는 것은 어리석기 때문입니다.

if (isAfterSunset) light.TurnOn();
else light.TurnOff();

내가 않는 무언가의 최적이 아닌 여기에 무슨 일이 일어나고 동의합니다. 어쩌면보기에는 너무 분명하지만, 첫 번째 문장은 "부울 매개 변수를 사용하여 행동을 결정하는 것을 피하는 것의 중요성"을 언급하는 것이며, 이것이 전체 질문의 기초입니다. API 사용자가 쉽게 할 수없는 일을 할 이유가 없습니다.


테스트를 수행하는지 모르겠습니다.이 경우 다음 사항도 고려하십시오.

테스트 관점에서는 인수가 더 어렵다. 모든 다양한 인수 조합이 올바르게 작동하도록 모든 테스트 사례를 작성하는 것이 어렵다고 상상해보십시오. 인수가 없으면 사소한 것입니다.


: 당신은 정말 여기 lede을 매장 한 행동 "을 결정하는 부울 매개 변수를 사용하여 [원문] 피할의 중요성을"당신의 첫 문장은 언급되어 ... "그리고 그 모든 질문에 대한 기본이다 내가 볼 수 없습니다. API 사용자가 쉽게 할 수없는 일을하는 이유입니다. " 이것은 흥미로운 점이지만 마지막 단락에서 자신의 주장을 훼손합니다.
와일드 카드

lede를 묻었습니까? 이 답변의 핵심은 "가능한 한 적은 인수를 사용하는 것"이며, 이는이 답변의 전반부에 설명되어 있습니다. 그 후의 모든 것은 단지 추가 정보입니다 : 모순되는 논쟁 (OP가 아닌 다른 사용자에 의한 논쟁)을 반박하고 모든 사람에게 적용되지 않는 것입니다.
R. Schmitz

마지막 단락은 제목 질문이 대답하기에 충분히 정의되지 않았 음을 분명히하려고합니다. OP는 "잘못된"것인지 묻지 만 누가 또는 무엇에 따라 말하지 않습니다. 컴파일러에 따르면? 유효한 코드처럼 보이므로 잘못되지 않았습니다. Clean Code 책에 따르면? 플래그 인수를 사용하므로 "잘못된"것입니다. 그러나 pragmatic> dogmatic이기 때문에 대신 "권장"을 작성합니다. 더 명확하게해야한다고 생각하십니까?
R. Schmitz

잠깐, 답변을 변호하는 것은 제목 질문이 답변하기에 너무 확실하지 않다는 것입니까? : D 좋아. 나는 실제로 내가 인용 한 요점이 흥미로운 신선한 취향이라고 생각했다.
와일드 카드

1
생생하게 지금 클리어; 잘 했어!
와일드 카드
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.