긴 메소드 리팩토링 : 그대로두고 메소드로 분리 vs 로컬 함수 사용


9

다음과 같은 긴 방법이 있다고 가정하십시오.

public void SomeLongMethod()
{
    // Some task #1
    ...

    // Some task #2
    ...
}

이 방법에는 별도의 방법이나 로컬 기능으로 이동해야하는 반복적 인 부분이 없습니다.

긴 방법이 코드 냄새라고 생각하는 사람들이 (나를 포함하여) 많이 있습니다. 또한 #region여기에 (s) 를 사용하는 것을 좋아하지 않으며 이것이 왜 나쁜지를 설명하는 매우 인기있는 답변이 있습니다.


그러나이 코드를 메소드로 분리하면

public void SomeLongMethod()
{
    Task1();

    Task2();
}

private void Task1()
{
    // Some task #1
    ...
}

private void Task2()
{
    // Some task #1
    ...
}

다음과 같은 문제가 있습니다.

  • 하나의 방법에 의해 내부적으로 사용되며, 어디 선가 문서화하는 것이한다는 의미는 어떤 정의를 클래스 정의의 범위를 오염 Task1Task2단지의 내부위한 것입니다 SomeLongMethod(또는 내 코드는이 아이디어를 추론 할 것이다 읽는 모든 사람).

  • 단일 SomeLongMethod메소드 내에서 한 번만 사용되는 메소드의 오염 된 IDE 자동 완성 (예 : Intellisense) .


이 메소드 코드를 로컬 함수 로 분리하면

public void SomeLongMethod()
{
    Task1();

    Task2();

    void Task1()
    {
        // Some task #1
        ...
    }

    void Task2()
    {
        // Some task #1
        ...
    }
}

그런 다음 별도의 방법의 단점이 없지만 원래 방법보다 나아 보이지는 않습니다 (적어도 나에게는).


어느 버전 SomeLongMethod이 더 유지 관리 가능하고 읽기 쉬운 지, 왜 그런가요?



@gnat 내 질문은 java가 아닌 c # 에만 해당됩니다 . 내 주요 관심사는 메소드로 분리되거나되지 않는 것이 아니라 고전적인 메소드 대 로컬 함수에 관한 것입니다.
Vadim Ovchinnikov

@gnat 또한 C #과 달리 AFAIK Java는 중첩 함수를 지원하지 않습니다.
Vadim Ovchinnikov

1
비공개 키워드는 반드시 '클래스 정의 범위'를 보호합니까?
Ewan

1
잠깐만 .. 수업이 얼마나 큽니까?
Ewan

답변:


13

자체 포함 된 작업은 자체 포함 된 방법으로 이동해야합니다. 이 목표를 무시할만큼 큰 결점이 없습니다.

클래스의 네임 스페이스를 오염 시킨다고 말하지만, 코드를 인수 분해 할 때 고려해야 할 절충안은 아닙니다. 미래의 강의 독자 (예 : 귀하)는 " 이 특정한 방법은 무엇을 하고 어떻게 변화된 요구 사항이 말한 것을 수행하도록 변경해야합니까?" " 클래스에있는 모든 메소드 의 목적과 의미는 무엇입니까 ? "따라서, 각 메소드를 이해하기 쉽게 (더 적은 요소를 가짐으로써) 전체 클래스를 이해하기 쉽게 만드는 것보다 훨씬 중요합니다. (더 적은 방법을 사용함으로써).

물론 작업이 실제로 자체 포함되어 있지는 않지만 이동하기 위해 일부 상태 변수가 필요한 경우 메소드 객체, 도우미 객체 또는 유사한 구성이 올바른 선택이 될 수 있습니다. 작업이 완전히 자체 포함되어 있고 응용 프로그램 도메인 전혀 연결되어 있지 않은 경우 (예 : 문자열 형식 일 경우) 완전히 다른 (유틸리티) 클래스로 들어가야합니다. 그러나 "모두가" "클래스 당 방법을 유지"하는 것이 최선의 보조 목표입니다.


그래서 당신은 로컬 함수가 아닌 메소드를위한 것입니다.
Vadim Ovchinnikov

2
@VadimOvchinnikov 현대적인 코드 폴딩 IDE에는 거의 차이가 없습니다. 로컬 함수의 가장 큰 장점은 매개 변수로 전달 해야하는 변수에 액세스 할 수 있다는 것입니다.하지만 변수가 많으면 작업이 처음부터 독립적이지 않았습니다.
Kilian Foth

6

나는 두 가지 접근법을 좋아하지 않습니다. 더 넓은 컨텍스트를 제공하지 않았지만 대부분 다음과 같이 보입니다.

여러 서비스의 기능을 단일 결과로 결합하여 일부 작업을 수행하는 클래스가 있습니다.

class SomeClass
{
    private readonly Service1 _service1;
    private readonly Service2 _service2;

    public void SomeLongMethod()
    {
        _service1.Task1();
        _service2.Task2();       
    }
}

각 서비스는 논리의 일부만 구현합니다. 이 servcice 만 할 수있는 특별한 것. 기본 API를 지원하는 메소드 이외의 다른 개인 메소드가있는 경우 쉽게 정렬 할 수 있으며 너무 많지 않아야합니다.

class Service1
{
    public void Task1()
    {
        // Some task #1
        ...
    }

    private void SomeHelperMethod() {}
}

class Service2
{
    void Task2()
    {
        // Some task #1
        ...
    }
}

결론은 코드를 gorup 메소드로 만들기 위해 영역을 작성하기 시작하면 논리를 새로운 서비스로 캡슐화하는 것에 대해 생각할 시간입니다.


2

메소드 내에 함수를 작성할 때의 문제점은 메소드 길이를 줄이지 않는다는 것입니다.

여분의 보호 수준을 '비공개 방법'을 원한다면 새로운 클래스를 만들 수 있습니다

public class BigClass
{
    public void SomeLongMethod();

    private class SomeLongMethodRunner
    {
        private void Task1();
        private void Task2();
    }
}

그러나 클래스의 클래스는 큰 추악합니다.


2

변수 및 메소드와 같은 언어 구성의 범위를 최소화하는 것이 좋습니다. 예를 들어 전역 변수를 피하십시오. 코드를 이해하기 쉽게 만들고 더 적은 위치에서 구성에 액세스 할 수 있기 때문에 오용을 피할 수 있습니다.

이것은 로컬 기능을 사용하는 것을 선호합니다.


1
흠, 많은 호출자 사이에 메소드를 공유하는 코드 ==를 반드시 재사용하십시오. 즉 범위를 최대화
Ewan

1

나는 긴 방법이 종종 코드 냄새라는 데 동의하지만, 그것이 전체 그림이라고 생각하지는 않지만 방법이 길어서 문제를 나타내는 이유입니다. 내 일반적인 규칙은 코드가 여러 개의 개별 작업을 수행하는 경우 해당 각 작업은 고유 한 방법이어야합니다. 저에게있어 코드 섹션이 반복적인지 아닌지는 중요합니다. 미래에 아무도 개별적으로 이들을 개별적으로 호출하고 싶지 않다는 것을 절대적으로 확신하지 않는 한 (그리고 그것은 매우 어려운 일입니다!) 다른 방법으로 넣습니다 (그리고 그것을 비공개로 만드십시오-매우 강력한 지표가되어야합니다) 당신은 그것이 수업 밖에서 사용될 것으로 기대하지 않습니다).

로컬 함수를 아직 사용하지 않았다고 고백해야하므로 이해가 여기에서 완전히 끝나지 않지만 제공 한 링크는 람다 식과 비슷한 방식으로 자주 사용될 것이라고 제안합니다 (여기에는 많은 유스 케이스가 있지만) 그것들이 람다보다 더 적절한 곳이거나 람다를 사용할 수없는 곳 은 람다 식과 비교하여 지역 함수를 참조하십시오 ). 여기서 나는 '다른'작업의 세분성에 도달 할 수 있다고 생각한다. 그것들이 상당히 사소한 경우 아마도 로컬 기능이 정상입니까? 반면에 나는 다른 방법에서 호출 된 것보다 코드를 이해하기 쉽고 유지 관리하기 쉽게 만든 behemoth 람다 식 (아마도 개발자가 최근 LINQ를 발견 한 곳)의 예를 보았습니다.

지역 기능 페이지는 말한다 :

'로컬 함수는 코드의 의도를 명확하게합니다. 코드를 읽는 사람은 포함 메소드를 제외하고 메소드를 호출 할 수 없음을 알 수 있습니다. 또한 팀 프로젝트의 경우 다른 개발자가 클래스 나 스투 트의 다른 곳에서 직접 메소드를 호출 할 수 없습니다. '

나는 이것이 실제로 MS와 함께 사용 이유라고 확신하지 못한다. 분석법의 범위 (이름과 설명과 함께)는 그 당시 의도가 무엇인지 분명히 밝혀야합니다 . 로컬 기능을 사용하면 다른 개발자가 더 성스러운 것으로 볼 수 있지만 잠재적으로 기능이 재사용되어야하는 변경이 향후 발생할 경우 자체 절차를 작성하고 로컬 기능을 그대로 둡니다 ; 따라서 코드 복제 문제가 발생합니다. 위의 인용문의 후자는 문장을 호출하기 전에 팀원이 개인 방법을 이해하도록 신뢰하지 않고 부적절하게 호출하면 관련이있을 수 있습니다 (따라서 교육이 더 나은 옵션 일지라도 결정에 영향을 줄 수 있음) .

요약하면, 일반적으로 메소드로 분리하는 것을 선호하지만 MS는 이유 때문에 로컬 함수를 작성 했으므로 절대 사용하지 않는다고 말할 수는 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.