1 주차 회고글을 보다가 어떤 분이 원시값 포장에 대해 언급하신 것을 보게 되었다.
원시값 포장이 뭔지 잘 모르기 때문에 이번 기회에 정리해 보려고 이 글을 작성하게 되었다.
🤔 원시값 포장??
원시값 포장이 뭘까? 이름 그대로 int
, String
, bytes
등과 같은 원시형 타입을 객체로 포장하는 것을 원시값 포장이라고 한다.
(반면, Collection 과 같은 자료형 타입을 포장하는 것을 일급 컬렉션이라고 한다. 이에 대해선 추후 알아보자.)
이게 뭔 말이야? 할 수도 있다. 그러니 코드 예시로 살펴보자.
int age = 20;
와 같은 변수를
Age age = new Age(20);
와 같이 객체로 포장하는 것을 원시값 포장이라고 말한다.
😳 뭐야 왜 객체로 포장해?
그러면 이제 왜 굳이 저렇게 객체로 포장할지 의문이 들 것이다.(내가 그랬다..ㅎㅎ)
왜 굳이 원시값 포장을 하는지 그 이유에 대해서 알아보자.
책임을 분산시킬 수 있다.
프리코스 1 주차 미션으로 숫자 야구에 대해서 구현해 본 적이 있으니까 이를 가지고 예시를 들어보겠다.
(직접 예시를 만들려다보니 부족한 부분이 많이 느껴지는데 너그러이 봐주면 감사하겠습니다ㅠㅠ)
public Player {
private List<Integer> numbers;
public Player(List<Intger> numbers) {
validateNumber(numbers); // 유효한 숫자인지 검증
validateLength(numbers); // 숫자가 3개인지 검증
this.numbers = numbers;
}
private void validateNumber(List<Integer> numbers) {
...
}
private void validateLength(List<Integer numbers) {
...
}
...
}
플레이어는 3개의 숫자가 들어있는 리스트를 가지고 정답인지 확인하려고 한다.
이때 3개의 숫자에 대한 검증이 필요하다.
- 숫자가 1~9 사이의 숫자인가?
- 총 3개의 숫자인가?
이와 같은 검증을 위 코드에서는 각각 validateNumber
, validateLength
를 통해 해주고 있다.
여기서 만약 숫자를 객체로 포장하면 아래와 같이 리팩터링 할 수 있다.
public BaseballNumber {
private int amount;
public BaseballNumber(int amount) {
validateNumber(amount);
this.amount = amount;
}
...
}
public Player {
private List<BaseballNumber> numbers;
public Player(List<BaseballNumber> numbers) {
validateLength(numbers); // 숫자가 3개인지 검증
this.numbers = numbers;
}
...
}
이러면 어떤 이점이 생길까?
숫자에 대한 검증은 BaseballNumber
라는 객체에게 넘기고 총 3개인지에 대한 검증은 Player
가 가진다.
즉, 책임이 분리되는 것이다.
Player
는 전체 숫자에 대해서만 관리하면 된다. 숫자가 유효한지(1~9 사이 숫자인지)에 대해서는 신경 쓰지 않아도 된다.
BaseballNumber
는 자신이 가지고 있는 숫자가 유효한지(1~9 사이 숫자인지)만 신경 쓰면 된다.
전체 숫자에 대해서 신경 쓰지 않아도 된다.(3자리 숫자인지)
이와 같이 책임을 분리시키면서 유지보수에 큰 도움을 줄 수 있다.
의도를 명확하게 표현해 실수를 방지할 수 있다.
public void transfer(int userId, int money) {
// 돈을 이체하는 로직
}
위와 같이 같은 자료형을 받는 로직의 경우 헷갈려서 둘의 순서를 잘못 입력할 수 있다.
10,000,000 원을 24번 유저에게 보내려고 하는데 잘못해서 transfer(10000000, 24)
와 같이 하여 10000000번 유저에게 24원을 보낼 수 있다.
public void transfer(UserId, userId, Money money) {
// 돈을 이체하는 로직
}
이런 경우 원시값 포장을 사용하게 된다면 실수를 방지할 수 있다.
transfer(new Money(10000000), new UserId(24)) // 컴파일 에러 발생!!
위와 같이 둘의 순서를 잘못 입력하여도 컴파일 단계에서 에러가 발생해 실수를 방지할 수 있다.
👀 그렇다면 모든 원시값들을 포장해야 돼??
그렇다면 여기서 또 의문이 생길 수 있다. 모든 원시값을 포장해야 할까?
모든 원시값을 포장하게 된다면 무수한 객체 생성으로 오히려 가독성을 저하시킬 수 있다.
그렇기 때문에 비즈니스 요구사항이 있는 원시값에 대해서만 포장하는 게 좋을 것 같다.
🌐 Referense
https://jaehee329.tistory.com/22
https://tecoble.techcourse.co.kr/post/2020-05-29-wrap-primitive-type/
'개발 스토리' 카테고리의 다른 글
toString 을 뷰에 맞게 재정의하면 안되는 이유 (0) | 2023.11.07 |
---|---|
Enum 을 꼭 사용해야 할까?? (4) | 2023.11.06 |
getter 를 지양해야하는 이유 (1) | 2023.10.28 |
JUnit에 대해 알아보고 사용해보기 👀 (1) | 2023.10.27 |
[우테코 API] Assetions, NsTest 에 대해 알아보기 (1) | 2023.10.26 |