태그 보관물: design

design

오버로드 된 메소드의 이름을 바꿔야합니까? Car findById(long id); List findByModel(String

다음 메소드를 포함하는 인터페이스를 가정하십시오.

Car find(long id);

List<Car> find(String model);

이렇게 이름을 바꾸는 것이 더 낫습니까?

Car findById(long id);

List findByModel(String model);

실제로,이 API를 사용하는 개발자는 초기 find()메소드의 가능한 인수를 알기 위해 인터페이스를 볼 필요가 없습니다 .

그래서 내 질문은 더 일반적입니다 : 가독성을 줄이기 때문에 코드에 과부하 된 메소드를 사용하면 어떤 이점이 있습니까?



답변

이것은 당신이 받아 들일 수있는 다른 많은 가독성 관행과 비교할 때 비교적 사소한 문제이므로, 방법의 이름을 짓는 방법은 대부분 맛의 문제라고 말하고 싶습니다.

그 말로, 당신이 그것에 대해 무언가를하려고한다면, 나는이 연습을 따를 것입니다 :

  • 만약에 …

    이 방법은 거의 동일한 계약을 따르지만 단순히 다른 입력에서 작동합니다 (개인 세금 ID 번호, 계정 번호 또는 이름과 생일로 계정을 조회 할 수있는 전화 사업자 상상). 여기에는 동일한 유형의 출력 반환 이 포함됩니다 .

  • 다음과 같은 경우 다른 이름을 사용하십시오.

    메소드는 실제로 다른 작업을 수행하거나 다른 경우와 같이 다른 출력을 반환합니다. 데이터베이스에 액세스하고 그렇지 않은 경우 다른 이름을 사용하는 것이 좋습니다.

    또한 반환 된 유형이 다른 경우 동사를 변경하여 다음을 나타냅니다.

    Car findById(long id);
    
    List findAllByModel(String model);
    

답변

모든 경우에 다른 이름을 사용하는 것이 좋습니다. 앞으로 언젠가 List<Car> findByMake(String make)와 달리 다른 방법을 추가하고 싶을 수도 있습니다 List<Car> findByModel(String model). 갑자기 모든 것을 부르는 것이 find말이되지 않습니다. 이름이 사용 방법에 대한 자세한 정보를 제공하는 경우, 메소드가 실수로 잘못 사용될 가능성도 줄어 듭니다.


답변

메소드의 이름을 바꾸면 더 이상 오버로드되지 않습니다. 오버로드가 코드를 읽기 어렵게 만들지는 않지만 구문이 명확하지 않으면 구현하기가 더 어려워 질 수 있습니다.

많은 언어는 매개 변수가 선택적 일 수 있고 선택적 매개 변수의 기본값이 내포 된 기능에 인터페이스를 제공하기위한 수단으로 메소드 오버로드를 사용합니다. 메서드 선언에서 기본 매개 변수 구문을 지원하지 않는 언어의 경우 특히 그렇습니다.

그래서 이것을하는 :

void MyMethod(int param1, int param2 = 10)
{
    ...
}

이 작업을 수행하지 않아도됩니다.

void MyMethod(int param1)
{
    MyMethod(param1, Param2Default);
}

void MyMethod(int param1, int param2)
{
    ....
}

어느 쪽이 더 읽기 쉽습니까? 개인적으로 두 번째 옵션, 특히 매개 변수 목록이 약간 길어질 때 선호하지만 API 전체에서 일관성이있는 한 실제로 중요하지 않다고 생각합니다.

오버로드의 어려움은 본질적으로 동일한 기능을 수행하고 매개 변수 목록은 동일하지만 반환 유형이 다른 함수를 원할 때 발생합니다. 대부분의 언어는 이름이 같지만 반환 유형이 다른 두 가지 방법을 구별하는 방법을 모릅니다. 이 시점에서 제네릭 사용, 매개 변수 인터페이스 변경 또는 반환 유형의 차이를 나타내는 메서드 중 하나의 이름 변경에 대해 생각해야합니다. 이와 같은 상황을 처리하기 위해 간단하고 명확한 이름 지정 체계를 설정하지 않으면 가독성이 큰 문제가 될 수 있습니다.

당신의 오버로드 된 메서드 이름 지정 GetSomething()GetSomethingEx()차이가 그들 사이의 유일한 차이가있는 반환 형식 인 경우 특히, 당신의 방법 사이에 무엇인지에 대해 많은 말을하려고하지 않습니다. 반면에, GetSomethingAsInt()그리고 GetSomethingAsString()방법이 무엇을하고 있는지에 대해 좀 더 말씀, 그리고 엄격하게 과부하 동안 수행하는 두 가지 방법이 유사한 일을 나타냅니다, 아직 다른 값 유형을 반환합니다. 메서드 이름을 지정할 수있는 다른 방법이 있다는 것을 알고 있지만 요점을 설명하기 위해 이러한 조잡한 예가해야합니다.

OPs 예제에서 메소드 매개 변수가 다르기 때문에 이름 바꾸기가 반드시 필요한 것은 아니지만 메소드 이름을 좀 더 구체적으로 지정하는 것이 조금 더 명확 해집니다. 결국 사용자에게 제공하려는 인터페이스 유형에 따라 달라집니다. 과부하 여부에 대한 결정은 독자 자신의 가독성에 기초하여 결정해서는 안됩니다. 오버로딩 메소드는 예를 들어 API 인터페이스를 단순화하고 개발자가 기억해야 할 메소드 수를 줄일 수 있습니다. 반면에, 인터페이스를 어느 정도 혼란스럽게 만들면 개발자가 메소드 문서를 읽고 어떤 형식을 이해해야 하는지를 이해할 수 있습니다. 유사하지만 설명 적으로 명명 된 여러 가지 방법을 사용하면 목적에 따라 메서드 이름을 읽는 것이 더 분명해질 수 있습니다.


답변

방법이 동일한 것을 반환하고 동일한 계약을 따르는 한 과부하를 선호하십시오. 오버로드는 호출 코드가 불필요하게 매개 변수 유형에 커밋되지 않도록합니다.

호출 함수가 검색 쿼리를 매개 변수로 받고에 대한 호출 전후에 다른 처리를 수행한다고 가정합니다 find.

void tryToSellCars(String which) {
    /* grab an airhorn, inflatable tube guy... */
    List<Car> cars = find(which);
    /* expound virtues of each car in detail... */
}

예를 들어 간단한 ID 문자열에서 완전한 기능을 갖춘 쿼리 객체로 어떤 이유로 든 해당 쿼리의 유형을 변경하려는 경우 함수 서명을 변경하여 호출 함수에서 해당 변경을 수행 할 수 있습니다 클래스에서 호출하는 메소드 변경에 대한 걱정없이 새 매개 변수 유형을 승인합니다.

void tryToSellCar(CarQuery which) {
    /* grab airhorn, inflate tube guy... */
    List<Car> cars = find(which)
    /* expound virtues of each car in detail... */
}

구현 findById하고 findByQueryObject별도로 구현하는 경우 해당 변경을 수행하기 위해 모든 호출을 찾아야합니다. 이 예에서는 한 단어 만 바꾸었고 끝났습니다.


답변