[내 코드가 그렇게 이상한가요?] 12장 메서드(함수):좋은 클래스에는 좋은 메서드가 있다
[메서드 설계 방법]
1. 반드시 현재 클래스의 인스턴스 변수 사용하기
다른 클래스의 인스턴스 변수를 변경하는 메서드는 좋지 않습니다. 응집도가 낮은 구조가 될 수 있기 때문입니다.
2. 불변을 활용해서 예상할 수 있는 메서드 만들기
불변을 활용해서 예상치 못한 동작 자체를 막을 수 있게 설계하기 바랍니다.
3. 묻지 말고 명령하라
메서드를 호출하는 쪽에서는 복잡한 처리를 하지 않는 것이 좋습니다.
(5장 참고)
다른 객체의 내부 상태(변수)를 기반으로 판단하거나 제어하려고 하지 말고, 메서드로 명령해서 객체가 알아서 판단하고 제어하도록 설계하라는 의미입니다.
- 인스턴스 변수를 private으로 변경해서, 외부에서 접근할 수 없게 합니다. (setter, getter 주의!!)
- 그리고 인스턴스 변수에 대한 제어는 외부에서 메서드로 명령하는 형태로 만듭니다.
- 상세한 판단과 제어는 명령을 받는 쪽에서 담당하게 합니다.
/** 장비하고 있는 방어구 목록 **/
class Equipments{
private boolean canChange;
private Equipment head;
private Equipment armor;
private Equipment arm;
/**
* 갑옷 장비하기
**/
void equipArmor(final Equipment newArmor){
if(canChange){
armor = newArmor;
}
}
/**
* 전체 장비 해제하기
*/
void deactivateAll(){
head = Equipment.EMPTY;
armor = Equipment.EMPTY;
arm = Equipment.EMPTY;
}
}
4. 커맨드/쿼리 분리
커맨드 쿼리 분리(CQS, Command-Query Separation) 패턴이란?
메서드는 커맨드 또는 쿼리 중에 하나만 하도록 설계해야 한다는 패턴입니다.
메서드 종류 구분 | 설명 |
커맨드 | 상태를 변경하는 것 |
쿼리 | 상태를 리턴하는 것 |
모디파이어 | 커맨드와 쿼리를 동시에 하는 것 |
수정 전 (상태 변경과 추출을 동시에 실행하는 메서드)
추출만 하고 싶거나 변경만 하고 싶을 때 지원하지 못합니다.
int gainAndGetPoint(){
//커맨드
point += 10;
//쿼리
return point;
}
수정 후 (커맨드와 쿼리를 각각의 메서드로 분리)
// 포인트 증가(커맨드)
void gainPoint(){
point += 10;
}
// 포인트 리턴(쿼리)
int getPoint(){
return point;
}
5. 매개변수
매개변수 설계 시 주의 사항
1) 불변 매개변수로 만들기 (final)
2) 플래그 매개변수 사용하지 않기
- 무슨 일을 하는지 이해하려면, 메서드 내부의 로직을 확인해야 하므로 가독성이 낮아집니다
- 전략 패턴 등 다른 구조로 설계하세요
3) null 전달하지 않기
- nullPointerException이 발생할 수 있으며, null을 확인해야 하므로 로직이 복잡해집니다
- 상태를 null로 나타내지 않고, Equipment.EMPTY 처럼 구현하세요
4) 출력 매개변수 사용하지 않기
- 새로운 객체를 만들어 return하는 형태로 만들기 (5장 참고)
5) 매개변수는 최대한 적게 사용하기
- 메서드에 매개변수가 많다는 것은 메서드가 여러 가지 기능을 처리한다는 의미입니다
6. 리턴 값
리턴 값 설계 시 주의 사항
1) '자료형'을 사용해서 리턴 값의 의도 나타내기
기본 자료형을 사용하지 말고, 독자적인 자료형을 사용해서 의도를 명확하게 나타내는 것이 좋습니다.
예시
class Price{
...
int add(final Price other){
return amount + other.amount;
}
}
int 자료형처럼 단순한 기본 자료형으로는 리턴한 값의 의미를 호출하는 쪽에 전달할 수 없습니다.
class Price{
...
Price add(final Price other){
final int added = amount + other.amount;
return new Price(added);
}
}
Price와 같이 독자적인 자료형을 사용하면, 의도를 보다 명확하게 나타낼 수 있습니다.
2) null 리턴하지 않기
3) 오류는 리턴 값으로 리턴하지 말고 예외 발생시키기