규칙 3. 모든 원시값과 문자열을 포장한다.
int, long, String 등 모든 원시값과 문자열을 객체로 포장해 사용하라는 원칙이다.
프로그래밍에서 변수는 '상태'로 사용될 수 있다. 여기서 상태는 단순 '자료'가 아닌 '정보'이다. 값을 나타내는 것뿐만 아니라, 값에 대한 비즈니스적인 의미도 포함한다는 뜻이다.
예시
여기 학생들의 점수를 입력하는 프로그램이 있다고 가정하자.
점수를 담는 score 변수를 따로 포장하지 않고 사용하였다. 하지만 점수의 유효성을 검증하는 로직이 점수를 매기는 메서드 안에 들어있다. 같은 정보인 score를 여러 메서드에서 사용한다면 같은 유효성 검사 로직을 메서드마다 추가해야 하는 번거로움이 있다.
public class GradingScore {
private static final int MIN_SCORE = 0; // 최저 점수
private static final int MAX_SCORE = 100; // 최대 점수
public void grade(int score) throws IllegalAccessException {
if (score < MIN_SCORE || score > MAX_SCORE) {
throw new IllegalAccessException("올바르지 않은 점수입니다.");
}
// 채점 로직
String grade = Grade.getGrade(score);
System.out.println(grade);
}
}
원시타입을 포장해 보자
다음은 원시타입이었던 score를 Score라는 별도의 클래스로 포장한 것이다.
객체로 포장하면서 점수의 유효성 검증에 대한 로직은 Score 클래스가 따로 담당하게 되었다. GradingScore의 grade메서드를 사용하려면 Score의 인스턴스를 생성해야만 한다. 이때 인스턴스를 생성하며 자연스럽게 유효성 검사를 할 수 있게 된다.
유효성 검사 로직을 클래스가 가지게 되면서 추가 요구사항이 발생했을 경우에도 클래스만 수정해 주면 된다. 더욱 유지보수성이 높은 코드가 된 것이다.
public class Score {
private static final int MIN_SCORE = 0; // 최저 점수
private static final int MAX_SCORE = 100; // 최대 점수
private int value;
public Score(int value) throws IllegalAccessException {
validate(value);
this.value = value;
}
private void validate(int value) throws IllegalAccessException {
if (value < MIN_SCORE || value > MAX_SCORE) {
throw new IllegalAccessException("올바르지 않은 점수입니다.");
}
}
}
public void grade(Score score) {
String grade = Grade.getGrade(score);
System.out.println(grade);
}
메서드의 시그니처 또한 명확해진다.
public void grade(int score)
public void grade(Score score)
원시 타입을 사용하는 것보다 포장된 클래스를 사용함으로 인해 어떤 값이 전달되어야 하는지 더욱 명확하게 알 수 있다. 또 메서드를 열어보지 않고 생성자를 확인하는 것만으로 올바른 값이 무엇인지 유추할 수 있게 된다.
참고자료