함수를 호출하는이 방법이 나쁜 습관입니까?


10

다음 코드가 있습니다.

public void moveCameraTo(Location location){
    moveCameraTo(location.getLatitude(), location.getLongitude());
}

public void moveCameraTo(double latitude, double longitude){
    LatLng latLng = new LatLng(latitude, longitude);
    moveCameraTo(latLng);
}

public void moveCameraTo(LatLng latLng){
    GoogleMap googleMap =  getGoogleMap();
    cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, INITIAL_MAP_ZOOM_LEVEL);
    googleMap.moveCamera(cameraUpdate);
}

나는 이런 식 LatLng으로 다른 수업에 무엇이 있는지 아는 책임을 제거한다고 생각합니다 .

그리고 함수를 호출하기 전에 데이터를 준비 할 필요가 없습니다.

어떻게 생각해?

이 접근법에는 이름이 있습니까? 실제로 나쁜 습관입니까?


2
언어의 내장 Method Overloading을 사용하여 Encapsulation을 다루는 것 같습니다. 좋지 않다. 코드를 도와 주거나 해칠 수있는 도구 일뿐입니다.
bitsoflogic

5
당신의 목표가이 클래스 LatLng의 고객들로부터 은닉 하는 Camera것이라면, 아마도 당신은 moveCameraTo(LatLng)되고 싶지 않을 것 public입니다.
bitsoflogic

답변에 제공된 조언 외에도 YAGNI를 언급하는 것이 좋습니다. 당신은 그것을 필요로하지 않습니다. 좋은 사용 사례가 있기 전에 API 메소드를 정의하지 마십시오.
Patrick Hughes

moveCameraToLocationmoveCameraTo/에 문제가 없습니다 moveCameraToCoords. 확실히 동일한 이름으로 Location / lat / long을 전달하고 싶지 않습니다.
insidesin

답변:


9

언어 메소드 오버로드 기능을 사용하여 호출자에게 위치 정보에 대한 메소드 종속성을 해결하는 대체 방법을 제공하고 있습니다. 그런 다음 카메라 업데이트의 나머지 작업을 해결하기 위해 다른 방법으로 위임합니다.

여기서 코드 냄새는 메소드를 호출하는 메소드 체인을 계속 확장하면 발생합니다. Location taking 메소드는 latLng taking 메소드를 호출하는 double taking 메소드를 호출합니다.이 메소드는 카메라를 업데이트하는 방법을 알고있는 것을 호출합니다.

긴 사슬은 가장 약한 고리만큼 강합니다. 체인의 각 확장은 작동 해야하는 코드의 발자국을 늘리 거나이 문제가 발생합니다.

각 방법이 제시된 문제를 해결하기 위해 가능한 한 가장 짧은 경로를 취하는 것이 훨씬 더 나은 설계입니다. 그렇다고 카메라 업데이트 방법을 알아야하는 것은 아닙니다. 각각은 위치 매개 변수 유형을 하나의 균일 한 유형으로 변환해야합니다.이 유형은이 유형이 제시 될 때 카메라를 업데이트하는 방법을 알고있는 것으로 전달 될 수 있습니다.

그렇게하면 다른 모든 것의 절반을 깰 필요없이 하나를 제거 할 수 있습니다.

치다:

public void moveCameraTo(Location location){
    moveCameraTo( new LatLng(location) );
}

이것은 위도 및 경도 LatLng문제를 처리합니다. 비용은 LatLng주변에 대한 지식을 확산시키는 데 있습니다. 그것은 비싸 보일 수도 있지만 내 경험에 따르면 매개 변수 객체를 설정하지 않으면 붙어 버리는 기본 강박 관념 보다 선호되는 대안 입니다.

경우 Locationrefactorable하지만, LatLng하지에 공장을 추가하여이 문제를 해결 고려 Location:

moveCameraTo( location.ToLatLng() );

이것은 또한 원시적 인 집착을 피할 수 있습니다.


1
나에게 그렇게 나쁘게 보이지는 않습니다. 그것은 소비자에게있어 단지 편의 일뿐입니다. 이것이 10 번 연결되거나 소비자가 실제로 이러한 옵션이 모두 필요하지 않은 경우 코드 냄새라고 부릅니다.
mcknz

1
그러나 각 함수에서 변환 복식에 대한 모든 논리를 LagLng로 또는 Location에서 LagLng로 바꾸는 대안은 무엇입니까?
Tlaloc-ES

@ Tlaloc-ES가 더 낫습니까?
candied_orange

@ Tlaloc-ES "트랜스포머"는 프리미티브가 도메인 로직에로드 될 때 한 번만 발생하면됩니다. DTO를 직렬화 해제 할 때 발생합니다. 그런 다음 모든 도메인 논리가 전달 LatLng되거나 Location객체 를 전달 합니다. 당신과 둘 사이의 관계를 표시 할 수 있습니다 New LatLng(Location)또는 Location.toLatLng()경우에 당신은 다른 하나에서 이동해야합니다.
bitsoflogic

1
@ Tlaloc-ES 관련 독서 : Martin Fowler의 FlagArgument . "얽힌 구현"섹션을 읽으십시오.
Marc.2377

8

솔루션에는 특별한 문제가 없습니다.

그러나 개인적으로 선호하는 것은 그러한 방법이 그렇게 유용하지 않다는 것입니다. 그리고 그들이 떨어져있는 물건의 인터페이스를 복잡하게 만듭니다.

void moveCameraTo(double latitude, double longitude)내가 아무 문제가 단순히 호출하지 참조로 정말, 코드를 단순화하지 않는 moveCameraTo(new LatLng(latitude, longitude));그것의 장소에서. 이 방법은 또한 원시적 인 집착의 냄새를 맡는다.

void moveCameraTo(Location location)더 나은 증명에 의해 해결 될 수있는 Location.ToLatLng()방법 및 호출 moveCameraTo(location.ToLatLng()).

이것이 C #이고 그러한 메소드가 실제로 필요한 경우 인스턴스 메소드 대신 확장 메소드로 선호합니다. 확장 메소드의 사용법은 추상화를 시도 하고이 인스턴스를 단위 테스트하면 정말 분명해질 것입니다. 간단한 변환으로 여러 과부하 대신 단일 방법을 가짜로 만드는 것이 훨씬 쉽습니다.

나는 이런 식으로 다른 클래스에서 LatLng가 무엇인지 아는 책임을 제거한다고 생각합니다.

이것이 왜 문제가 될 지 이유가 없습니다. 코드가 포함하는 클래스를 참조 void moveCameraTo(LatLng latLng)하는 한 여전히 간접적으로 의존합니다 LatLng. 해당 클래스가 직접 인스턴스화되지 않은 경우에도 마찬가지입니다.

그리고 함수를 호출하기 전에 데이터를 준비 할 필요가 없습니다.

무슨 말인지 모르겠어요 새 인스턴스를 만들거나 클래스를 다른 클래스로 변환하는 것을 의미한다면 아무런 문제가 없습니다.

그것에 대해 생각하면서, 내가 말하는 것은 .NET 자체의 API 디자인에서도 지원된다고 생각합니다. 역사적으로 많은 .NET 클래스는 다른 매개 변수와 간단한 변환을 통해 많은 과부하가 발생하는 접근 방식을 따릅니다. 그러나 그것은 확장 방법이 존재하기 전이었습니다. 최신 .NET 클래스는 자체 API에서 더 가벼우 며 매개 변수 오버로드가있는 메서드가있는 경우 확장 메서드로 제공됩니다. 더 오래된 예는 NLog ILogger 로, 로그에 쓸 수있는 수십 개의 과부하가 있습니다. 총 3 개의 메서드가있는 최신 Microsoft.Extensions.Logging.ILogger 와 로깅 자체를 계산하는 경우에는 1 개만 비교하십시오 . 그러나 확장 방법 으로 많은 도우미와 다양한 매개 변수가 있습니다 .

이 답변은 일부 언어에는 이와 같은 디자인을 더 좋게 만드는 도구가 있음을 보여줍니다. 나는 많은 Java를 모르므로 동등한 것이 있는지 확실하지 않습니다. 그러나 일반 정적 메소드를 사용하는 것조차 옵션이 될 수 있습니다.


이유는 확실하지 않지만 경쟁 답변이 있음에도 불구 하고이 답변을 응원하는 것으로 나타났습니다. 난 당신이 요점을 더 잘 관리했다고 생각합니다. 내 유일한 피드백은이 문제를 다루는 모든 사람이 .NET에 있지는 않다는 것을 기억하는 것입니다. +1
candied_orange

@candied_orange 맞습니다. 이제 OP의 질문을 더 잘 보았습니다 .C #보다 Java와 비슷합니다.
Euphoric

정말 사용하지 않는 문제가 있다고 생각 moveCameraTo(new LatLng(latitude, longitude));프로젝트의 아무 곳에서,하지만 난 그 직접 moveCametaTo (latLng를가), 당신은 문자열과 같은, 또는 경로 클래스와 같은 경로를 전달할 수있는 자바 파일처럼 더 명확 사용하는 것입니다 생각
Tlaloc-ES

1

이름이 있으면 올바른 이름이 무엇인지 잘 모르겠지만 좋은 습관입니다. 여러 오버로드를 노출시켜 호출 클래스가 사용할 매개 변수 세트를 결정할 수 있도록합니다. 당신이 말했듯이, 다른 클래스는 LatLng객체가 무엇인지 알지 못하지만 그것을 알 수 있습니다 Location.

한 메소드에서 다른 메소드를 호출하는 것도 중요합니다. 이러한 메소드에서 중복 된 코드를 원하지 않기 때문입니다. 작업을 수행 한 방법으로 하나의 방법을 선택하고 다른 방법으로 직접 또는 간접적으로 호출하도록합니다.


1

메소드의 종류를 사용하고 싶다면 메소드 오버로드 기능 일뿐입니다.

그러나 LatLng가 무엇인지 아는 책임은 제거 되지 않습니다 . 초기화 중이기 때문에 LatLng latLng = new LatLng(latitude, longitude). 이것은 전적으로 의존합니다 LatLng. (초기화가 종속성 문제인 이유를 이해하려면 종속성 주입을 확인할 수 있습니다. ) 오버로드 된 메소드를 작성하면 신경 쓰지 않는 클라이언트에게 도움이됩니다 LatLng. 당신이 이것을 의미한다면, 그것은 또한 좋지만 나는 그것이 접근법이라고 생각하지 않습니다. 클라이언트를위한 많은 서비스 방법입니다.

따라서 아키텍처를 설계하는 두 가지 옵션이 있습니다.

  1. 오버로드 된 많은 메소드를 작성하여 클라이언트에 제공하십시오.
  2. 인터페이스 또는 구체적 클래스로 매개 변수가 필요한 오버로드 된 메소드를 거의 작성하지 마십시오.

기본 유형이 매개 변수 (옵션 1)가 필요한 메소드를 만들 때 가능한 한 도망칩니다. 비즈니스가 많이 변하고 메소드 매개 변수를 재생해야하는 경우, 모든 호출자 기능을 변경하고 구현하기가 실제로 어렵습니다.

이 대신 인터페이스 (종속성 주입)를 사용하십시오. 비용이 많이 들고 시간이 더 걸린다고 생각되면 클래스를 사용하고 매퍼 확장 메소드를 제공하십시오 (옵션 2).

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