이것은 긴 패턴을 일련의 람다로 대체하는 좋은 패턴입니까?


14

나는 최근에 다음과 같은 상황에 처해있다.

class A{
public:
    void calculate(T inputs);
}

첫째, A물리적 세계의 물체를 나타내며, 이는 계급을 나누지 않는 강력한 주장입니다. 이제는 calculate()길고 복잡한 기능으로 밝혀졌습니다. 나는 세 가지 가능한 구조를 인식합니다.

  • 텍스트의 벽으로 작성하십시오-장점-모든 정보가 한 곳에 있습니다
  • private클래스에서 유틸리티 함수를 작성 하고 calculate신체에서 단점을 사용하십시오-클래스의 나머지 부분은 그 메소드에 대해 알지 못하거나 돌 보거나 이해하지 못합니다
  • calculate다음과 같이 작성 하십시오.

    void A::calculate(T inputs){    
        auto lambda1 = () [] {};    
        auto lambda2 = () [] {};    
        auto lambda3 = () [] {};
    
        lambda1(inputs.first_logical_chunk);
        lambda2(inputs.second_logical_chunk);
        lambda3(inputs.third_logical_chunk);
    }

이것이 좋은 습관인지 나쁜 습관으로 간주 될 수 있습니까? 이 접근 방식에 문제가 있습니까? 대체로 동일한 상황에 다시 직면 할 때 이것이 좋은 접근 방식으로 고려해야합니까?


편집하다:

class A{
    ...
public:
    // Reconfiguration of the algorithm.
    void set_colour(double colour);
    void set_density(double density);
    void set_predelay(unsigned long microseconds);
    void set_reverb_time(double reverb_time, double room_size);
    void set_drywet(double left, double right);
    void set_room_size(double value);;

private:
    // Sub-model objects.
    ...
}

모든 방법들 :

  • 가치를 얻다
  • 상태를 사용하지 않고 다른 값을 계산
  • 상태를 변경하려면 "하위 모델 객체"중 일부를 호출하십시오.

를 제외 set_room_size()하고 이러한 메소드는 단순히 요청 된 값을 하위 오브젝트에 전달합니다. set_room_size()반면에, 모호한 수식의 두 화면을 수행 한 다음 (2) 하위 오브젝트 세터를 호출하는 화면의 절반을 수행하여 다양한 결과를 적용합니다. 따라서 함수를 두 개의 람다로 분리하고 함수 끝에서 호출합니다. 더 논리적 인 덩어리로 나눌 수 있다면 더 많은 람다를 분리했을 것입니다.

어쨌든, 현재 질문의 목표는 그러한 사고 방식이 지속되어야하는지 또는 가치를 추가하지 않는 것이 최선인지 결정하는 것입니다 (가독성, 유지 관리 성, 디버그 가능성 등).


2
람다를 사용하면 함수 호출이하지 않을 것이라고 생각하는 것은 무엇입니까?
Blrfl

1
Firstly, A represents an object in the physical world, which is a strong argument for not splitting the class up.분명히 A나타내는 데이터 객체에 대한 존재할 수 물리적 세계를. A실제 객체 가 없는 인스턴스와의 인스턴스가 없는 실제 객체를 가질 수 있으므로 인스턴스를 A동일하게 취급하는 것은 무의미합니다.
Doval

@Blrfl, 캡슐화-아무도 calculate()그 하위 기능에 대해 알 것입니다.
Vorac

이러한 모든 계산이 just A와 관련이 있다면 약간의 오차가 있습니다.
Blrfl

1
"먼저, A실세계의 물체를 나타내며, 이것은 계급을 나누지 않는 강력한 주장입니다." 불행히도 나는 프로그래밍을 시작할 때 이것을 말했다. 말 하키라는 것을 깨닫기까지 몇 년이 걸렸습니다. 그것은의 끔찍한 그룹 것들에 이유. 나는 무엇을 명확하게 할 수 있습니다 (적어도 내 만족) 그룹 일에 좋은 이유가 있지만, 그 중 하나는 당신이 지금 당장 폐기해야 하나입니다. 결국 "좋은 코드"는 모두 올바르게 작동하고 이해하기 쉽고 상대적으로 변경하기 쉽다는 것입니다 (예 : 변경 사항에 이상한 부작용이 없음).
jpmc26

답변:


13

아니요, 일반적으로 좋은 패턴은 아닙니다

당신이하고있는 일은 람다를 사용하여 함수를 더 작은 함수로 나누는 것입니다. 그러나 함수를 분해 하는 데 훨씬 유용한 도구 인 함수가 있습니다.

람다는 당신이 본 것처럼 작동하지만, 단순히 함수를 로컬 비트로 나누는 것보다 훨씬많은 것을 의미 합니다. 람다는

  • 마감. 람다 내부의 외부 범위에서 변수를 사용할 수 있습니다. 이것은 매우 강력하고 복잡합니다.
  • 재 할당. 예제를 통해 할당하기가 어려워 지더라도 항상 코드가 언제든지 함수를 교체 할 수 있다는 아이디어에주의를 기울여야합니다.
  • 일류 기능. 람다 함수를 다른 함수에 전달하여 "함수 프로그래밍"이라고하는 것을 수행 할 수 있습니다.

람다를 믹스로 가져 오는 순간, 다음 개발자가 코드를 살펴보면 코드 작동 방식을 확인하기 위해 모든 규칙을 즉시 정신적으로로드해야합니다. 그들은 당신이 그 기능을 모두 사용하지 않을 것이라는 것을 모른다. 이것은 대안에 비해 매우 비쌉니다.

뜰을 만드는 데 백호를 사용하는 것과 같습니다. 당신은 당신이 올해의 꽃에 작은 구멍을 파기 위해 그것을 사용한다는 것을 알고 있지만 이웃은 긴장할 것입니다.

소스 코드를 시각적으로 그룹화하는 것만 고려하십시오. 컴파일러는 실제로 람다로 카레를 처리하는 것을 신경 쓰지 않습니다. 사실, 옵티마이 저가 컴파일 할 때 방금 수행 한 모든 것을 즉시 취소 할 것으로 기대합니다. 당신은 순전히 다음 독자에게 음식을 제공하고 있습니다 (방법론에 동의하지 않더라도 감사합니다! 당신이하고있는 모든 기능을 그룹화합니다.

  • 소스 코드 스트림 내에 로컬로 배치 된 함수는 람다를 호출하지 않고도 마찬가지로 수행됩니다. 다시 한 번 중요한 것은 독자가 읽을 수 있다는 것입니다.
  • 함수 상단에 "우리는이 함수를 세 부분으로 나누고 있습니다"라고 말하고 // ------------------각 부분 사이에 긴 줄 이옵니다.
  • 계산의 각 부분을 자체 범위에 넣을 수도 있습니다. 이는 부품간에 변수 공유가 없다는 것을 의심 할 여지없이 즉시 입증 할 수있는 보너스입니다.

편집 : 예제 코드로 편집 내용을 볼 때 주석이 제안하는 경계를 시행하기 위해 괄호와 함께 주석 표시가 가장 깨끗합니다. 그러나 다른 기능에서 재사용 할 수있는 기능이 있으면 대신 기능을 사용하는 것이 좋습니다.

void A::set_room_size(double value)
{
    {
        // Part 1: {description of part 1}
        ...
    }
    // ------------------------
    {
        // Part 2: {description of part 2}
        ...
    }
    // ------------------------
    {
        // Part 3: {description of part 3}
        ...
    }
}

객관적인 숫자는 아니지만 람다 함수의 존재만으로도 각 코드 라인에 약 10 배 더주의를 기울일 수 있다고 주관적으로 주장합니다. (같은 코드의 결백을 찾고 라인 count++)
콜트 암몬

좋은 지적입니다. 나는 람다-(1) 로컬로 인접한 코드와 로컬 범위 (파일 수준 함수에 의해 손실 될 것입니다) (2) 컴파일러는 코드 세그먼트간에 로컬 변수가 공유되지 않도록하는 접근 방식의 장점 중 몇 가지를 봅니다. 따라서 이러한 이점은 블록 으로 분리 하고 범위 에서 공유 데이터를 선언 calculate()하여 보존 할 수 있습니다 . 나는 람다가 포착되지 않는 것을 보았을 때 독자는 람다의 힘에 의해 방해받지 않을 것이라고 생각했습니다. {}calculate()
Vorac

"나는 람다가 포착되지 않는 것을 보았을 때 독자는 람다의 힘으로 방해받지 않을 것입니다." 그것은 실제로 공정하지만 논쟁적인 말로 언어학의 핵심에 부딪칩니다. 단어에는 일반적으로 그 의미를 넘어서는 의미가 있습니다. 내 의미 lambda가 불공평한지 또는 사람들이 엄격한 표시를 따르도록 무례하게 강요 하는지 여부 는 쉬운 질문이 아닙니다. 사실,하지 않을 수 있습니다 완전히 사용하기에 허용 lambda기업에서 그런 식으로, 그리고 완전히 내 회사에서 받아 들일 수없는, 그리고 둘 중 하나는 실제로 잘못있다!
Cort Ammon

람다의 의미에 대한 나의 의견은 내가 C + 11이 아니라 C ++ 03에서 자랐다는 사실에서 나옵니다. 나는 함수 lambda와 같은 부족으로 C ++이 손상을 입은 특정 장소에 대한 감사를 개발하는 데 수년을 보냈다 for_each. 따라서 lambda스팟이 발생하기 쉬운 문제 중 하나에 맞지 않는 것을 볼 때 가장 먼저 가정하는 것은 함수형 프로그래밍에 사용될 가능성이 있다는 것입니다. 많은 개발자에게 기능적 프로그래밍은 절차 적 또는 OO 프로그래밍과 완전히 다른 사고 방식입니다.
Cort Ammon

설명해 주셔서 감사합니다. 나는 초보자 프로그래머이며 이제 습관이 쌓이기 전에 물었다.
Vorac

20

나는 당신이 나쁜 가정을했다고 생각합니다.

첫째, A는 실제 세계의 물체를 나타내며, 이는 계급을 나누지 않는 강력한 주장입니다.

나는 이것에 동의하지 않습니다. 예를 들어, 자동차를 대표하는 클래스가 있다면, 분명히 작은 클래스가 타이어를 나타내기를 원하기 때문에 분리하고 싶습니다.

이 기능을 더 작은 개인 기능으로 분할해야합니다. 클래스의 다른 부분과 실제로 분리 된 것으로 보이면 클래스가 분리되어야한다는 신호일 수 있습니다. 물론 명백한 예 없이는 말하기가 어렵습니다.

이 경우 람다 함수를 사용하는 것이 실제로 코드를 깨끗하게하지 않기 때문에 이점을 보지 못합니다. 그것들은 함수형 프로그래밍을 돕기 위해 만들어졌지만, 그렇지 않습니다.

작성한 내용은 Javascript 스타일의 중첩 함수 객체와 약간 비슷합니다. 다시 한 번 그들이 서로 밀접하게 속한다는 표시입니다. 그들을 위해 별도의 수업을 만들어서는 안된다고 확신하십니까?

요약하면, 이것이 좋은 패턴이라고 생각하지 않습니다.

최신 정보

의미있는 클래스에서이 기능을 캡슐화하는 방법이 보이지 않으면 클래스 멤버 가 아닌 파일 범위 헬퍼 함수를 ​​작성할 수 있습니다 . 이것은 결국 C ++이며 OO 디자인은 필수는 아닙니다.


합리적으로 들리지만 구현을 상상하기는 어렵습니다. 정적 메소드가있는 파일 범위 클래스? 클래스 정의 내부 A(개인 다른 모든 방법과 어쩌면 펑)? 내부에서 선언되고 정의 된 클래스 calculate()(이것은 내 람다 예제와 매우 비슷합니다). 명확히하기 위해, 모든 방법이 간단한 calculate()방법 calculate_1(), calculate_2()등 중 하나입니다.이 화면은 2 화면입니다.
Vorac

@Vorac : 왜 calculate()다른 모든 방법보다 훨씬 길습니까?
케빈

@Vorac 코드를 보지 않으면 도움이되지 않습니다. 당신은 또한 그것을 게시 할 수 있습니까?
Gábor Angyal

@Kevin, 모든 공식은 요구 사항에 나와 있습니다. 코드가 게시되었습니다.
Vorac

4
내가 할 수 있다면 이걸 100 번 찬성 했어 "실제 세계에서 객체 모델링"은 객체 디자인 죽음의 소용돌이의 시작입니다. 모든 코드에서 거대한 적기입니다.
Fred the Magic Wonder Dog
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.