Java

메서드 시그니처를 신중히 설계하라.

일태우 2021. 2. 9. 16:14
반응형

메서드 시그니처를 신중히 설계하라

개별 아이템으로 두기 애매한 API 설계 요령들을 모아 놓았다. 배우기 쉽고, 쓰기 쉽고, 오류 가능성이 적은 API를 만들기 위함이다.

메서드 이름을 신중히 짓자.

항상 표준 명명 규칙(아이템68)을 따라야 한다. 이해할수 있고, 같은 패키지에 속한 다른 이름들과 일관되게 짓는 게 최우선 목표다. 그다음은 개발자 커뮤니티에서 널리 받아들여지는 이름을 사용하는 것이다. 긴 이름은 피하자. 애매하면 자바 라이브러리의 API 가이드를 참조하라. 자바 라이브러리가 워낙 방대하다 보니 일관되지 않은 이름도 제법 많지만 대부분은 납득할 수준이다.

편의 메서드를 너무 많이 만들지 말자

모든 메서드는 각각 자신의 소임을 다해야 한다. 메서드가 너무많으면 익히고 사용하고 문서화하고 테스트하고 유지보수하기 어렵다. 인터페이스도 마찬가지다. 클래스나 인터페이스는 자신의 각 기능을 완벽히 수행하는 메서드로 제공해야 한다. 아주 자주 쓰일 경우에만 별도의 약칭 메서드를 두기 바란다.

매개변수 목록은 짧게 유지하라

4개 이하가 좋다. 4개가 넘어가면 매개변수를 기억하기 어렵다. 이 제한으 넘으면 api 문서를 끼고 개발해야 한다. 특히 같은 타입의 매개변수 여러개가 연달아 나오는 경우가 해롭다. 과하게 긴 매개변수 목록을 짧게 줄여주는 기술 세 가지를 소개한다.

  1. 여러 메서드로 쪼갠다. 쪼개진 각각 메서드는 원래 매개변수 목록의 부분집합을 받는다 잘못하면 메서드가 많아지지만 직교성을 높여 오히려 메서드 수를 줄여주는 효과도 있다. java.util.list 인터페이스가 좋은 예다. 리스트에서 주어진 원소의 인덱스를 찾야 하는데, 전체 리스트가 아니라 지정된 범위의 부분리스트ㅇ서의 인덱스를 찾는다고 해보자. 이 기능을 하나의 메서드로 구현하려면 '부분리스트의 시작', '부분리스트의 끝', '찾을 원소'까지 총 3개의 매개변수가 필욯요하다 그런데 LIST는 부분리스트를 반환하는 subList 메서드와 주어진 원소의 인덱스를 반환하는 indexOf 메서드를 제공한다.
  2. 매개변수 여러 개를 묶어주는 도우미 클래스를 만드는 것. 일반적으로 이런 도우미 클래스는 정적 멤버 클래스(아이템 24)로 둔다. 특히 잇따른 매개변수 몇 개를 독립된 하나의 개념으로 볼 수 있을때 추천하는 기법이다. 예를들어 카드게임 클래스를 만든다고 해보자 즉러면 메서드를 호출할 때 카드의 숫자(rank)와 무늬(suit)를 뜻하는 두 매개변수를 항상 같은 순서로 전달할 것이다. 따라서 이 둘을 묶는 도우미 클래스를 만들어 하나의 매개변수로 주고받으면 API는 물론 클래스 내부 구현도 깔끔해질 것이다.
  3. 앞의 두 방법을 혼합하여, 객체 생성에 사용한 빌더 패턴(아이템 2)을 메서드 호출에 응용한다고 보면 된다. 이 기법은 매개변수가 많을 때, 특히 그중 일부는 생략해도 괜찮을 때 도움이 된다. 먼저 모든 매개변수를 하나로 추상화한 객체를 정의하고, 클라이언트에서 이 객체의 세터(setter) 메서드를 호출해 필요한 값을 설정하게 하는 것이다. 이때 각 세터 메서드는 매개변수 하나 혹은 서로 연관된 몇개 만 설정하게 한다. 클라이언트는 먼저 필요한 매개변수를 다 설정한 다음, execute 메서드를 호출해 앞서 설정한 매개변수들의 유효성을 검사한다. 마지막으로 설정이 완료된 객체를 넘겨 원하는 계산을 수행한다.매개변수 타입으로는 클래스보다 인터페이스가 더 낫다.매개변수로 적합한 인터페이스가 있다면 (이를 구현한 클래스가 아닌) 그 인터페이스를 직접 사용하라.예를 들어 메서드에 HashMap을 넘길 일은 전혀 없다. 대신 Map을 사용하자. 그러면 HashMap뿐 아니라 TreeMap, ConcurrentHashMap, TreeMap의 부분맵 등 어떤 Map 구현체도 인수로 건넬 수 있다. 심지어 아직 존재하지 않는 Map도 가능하다. 인터페이스 대신 클래스를 사용하면 클라이언트에게 특정 구현체만 사용하도록 제한하는 꼴이며, 혹시라도 입력 데이터가 다른 형태로 존재한다면 명시한 특정 구현체의 객체로 옮겨담느라 비싼 복사비용을 치러야 한다.boolean 보다는 원소 2개짜리 열거타입이 낫다.(메서드 이름상 boolean을 받아야 의미가 명확할 때를 제외하고)열거 타입을 사용하면 코드를 읽고 쓰기가 쉬워진다. 나중에 선택지를 추가하기도 쉽다. 예를들어 다음은 화씨온도와 섭씨온도를 원소로 정의한 열거타입이다.
public enum TemperatureScale { FAHRENHEIT, CELSIUS }

온도계 클래스의 정적 팩터리 메서드가 이 열거 타입을 입력받아 적합한 온도계 인스턴스를 생성해준다고 해보자.

 

확실히 Thermometer.newInstance(true)보다는 Thermometer.newInstance(TemperatureScale.CELSIUS)가 하는 일을 훨씬 명확히 알려준다.

 

나중에 캘빈온도도 지원해야 한다면 Thermometer에 또다른 정적 메서드를 추가할 필요 없이 TemperatureScale 열거 타입에 추가해주면된다.

 

또한 온도 단위에 대한 의존성을 개별 열거 타입상수의 메서드 안으로 리팩터링해 넣을 수도 있다. 예컨대 double 값을 받아 섭씨온도로 변환해주는 메서드를 열거 타입 상수 각각에 정의해둘 수도 있다.

 

출처: effective java 51

반응형