영호
원시값 포장을 왜 할까? 본문
들어가며
이번 글에서는 프리코스부터 레벨 1 미션동안 빠지지 않던 요구사항인 원시값 포장에 대해 미션을 진행하면서 이것이 왜 필요한지, 반드시 적용해야 하는지에 대한 주관적인 입장을 정리해보겠습니다.
우선 메서드의 파라미터에 동일한 타입이 존재할 경우 오용을 방지할 수 있다고 생각합니다.
파라미터에 동일한 타입이 존재하는 예시
public class Person {
private final String name;
private final String address;
Person(final String name, final String address) {
this.name = name;
this.address = address;
}
}
위 코드처럼 작성한 경우 클라이언트에서 아래와 같은 실수를 할 수 있습니다.
public class Application {
public static void main(String[] args) {
final Person person = new Person("잠실", "레오");
}
}
"이름, 주소"순서로 인자로 넘어가야 하지만 "주소, 이름" 순서로 인자가 넘어갔기 때문에 해당 인스턴스는 "잠실에 사는 레오"가 아닌 "레오에 사는 잠실"이 됐습니다.
그렇다면 이와 같은 오용을 막기 위해서는 어떤 방법이 있을까요? 원시값 포장을 통해 위와 같은 오용을 막을 수 있습니다.
원시값 포장
우선 이름을 포장해 보겠습니다.
public class Name {
private final String name;
public Name(final String name) {
// 유효성 검사~~~
this.name = name;
}
}
name을 인스턴스 변수로 갖는 Name객체를 생성했습니다. 만약 시스템 요구사항에 "이름은 1~5글자 사이만 가능하다!"가 있을 경우 해당 유효성 검사를 생성자에서 진행함으로써 요구사항에 맞는 도메인 인스턴스를 생성할 수 있습니다.
이번엔, 주소에 대해 포장해 보겠습니다.
public class address {
private final String nation;
private final String city;
address(final String nation, final String city) {
// 유효성 검사~~~
this.nation = nation;
this.city = city;
}
}
이름과 마찬가지로 원시값 포장을 통해 요구사항을 만족하는 도메인 객체를 생성할 수 있습니다.
이제 String name, String address를 받던 Person의 생성자를 수정해보겠습니다.
public class Person {
private final Name name;
private final Address address;
Person(final Name name, final Address address) {
this.name = name;
this.address = address;
}
}
이후 Person인스턴스를 생성하는 코드를 보면 컴파일 시점에 잘못된 타입을 건네주기 때문에 컴파일 오류가 발생하는 것을 확인할 수 있습니다.
내가 생각하는 장점
- 요구사항을 만족하는 도메인 객체를 보장할 수 있다.
- 동일한 primitive타입의 파라미터가 있을 경우 이를 클라이언트 측에서 오용할 수 있지만, 이를 방지한다.
- 캡슐화에 도움이 된다.
- 인스턴스 변수로 원시값을 가지고 있기 때문에, 적절한 책임을 가지고 있는 객체가 탄생할 수 있다고 생각합니다.
- 예를 들어, 로또 당첨 번호를 원시값으로 포장해 LottoNumber가 있다고 가정한 뒤, 사용자가 뽑은 로또 번호에 대해 LottoNumber와 비교해 당첨여부를 판단해 boolean값을 반환하는 책임을 가질 수 있다고 생각합니다.
그러면 모든 원시값을 무조건 포장해야 할까?
- 원시값 포장을 위해선 별도의 클래스를 생성하는 별도의 작업이 요구됩니다. 그렇기 때문에 개인적으로 요구사항이 있는 원시타입의 경우에 한해 포장을 해줘도 괜찮지 않을까?라는 입장입니다.
- 예를 들어, 자동차 경주 게임의 시도 횟수는 최대 10번까지 가능하다.라는 요구사항이 있을 경우 이 시도 횟수를 TryCount로 만들어 요구사항에 맞는 객체를 생성할 수 있습니다.
- 그리고, 게임 진행에 있어 앞으로 게임을 계속 진행할 수 있는지 판단하는 책임도 부여할 수 있는 객체가 될 수 있습니다.
지금까지 원시값 포장에 대한 저의 주관적인 생각이었습니다~