조종 다음은 개발
article thumbnail

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. 숫자가 1~9 사이의 숫자인가?
  2. 총 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

 

[Java] 원시값을 포장해 사용하자

객체지향 생활체조 원칙에선 '모든 원시값과 문자열을 포장한다'라는 규칙이 존재한다. 객체지향적 설계를 위해 원시값을 포장해 얻는 이점이 무엇이며, 어떻게 사용하면 좋을까? 원시값을 포

jaehee329.tistory.com

https://00h0.tistory.com/79

 

원시값 포장을 왜 할까?

들어가며 이번 글에서는 프리코스부터 레벨 1 미션동안 빠지지 않던 요구사항인 원시값 포장에 대해 미션을 진행하면서 이것이 왜 필요한지, 반드시 적용해야 하는지에 대한 주관적인 입장을

00h0.tistory.com

https://tecoble.techcourse.co.kr/post/2020-05-29-wrap-primitive-type/

 

원시 타입을 포장해야 하는 이유

변수를 선언하는 방법에는 두 가지가 있다. 원시 타입의 변수를 선언하는 방법과, 원시 타입의 변수를 객체로 포장한 변수를 선언하는 방법이 있다. (Collection…

tecoble.techcourse.co.kr

 

profile

조종 다음은 개발

@타칸

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!