본문 바로가기
Study/Java

[Java] 원시값 포장이란?

by 검프 2021. 3. 15.

원시값 포장이라는 말이 모호해요.

우선 원시값 포장이라는 말이 어디서 나왔는지 확인해볼 필요가 있어요.

모든 원시값과 문자열을 포장하라 라는 말은 객체지향 체조 원칙에서 나온 말이에요.

 

원시값 포장이 왜 필요하죠?

원시값 포장은 Primitive Obsession Anti Pattern(도메인의 객체를 나타내기 위해 primitive타입을 쓰는 나쁜 습관)을 피하기 위해 필요해요.

즉, 원시값 포장은 원시 유형의 값(변수명)을 이용해 의미를 나타내지 않고, 의미있는 객체로 포장한다는 개념이라 볼 수 있어요.

 

아직 설명이 부족해요.

게임을 위한 배팅 금액을 아래와 같이 나타낼 수 있어요.

public class Foo {
    private int bettingMoney;

    public void addMoney(final int money) {
            this.bettingMoney += money;
    }
} 

여기선 bettingMoney에 대해 의문점이 많아요 (과연 int인가, bettingMoney가 음수일 수 있나? 등등).

 

하지만 아래와 같이 나타낸다면, 유효성 검사, 동등성 검사, 불변을 BettingMoney 객체 내부에서 관리할 수 있어요.

public class Foo {
    private BettingMoney bettingMoney;

    public void addMoney(final int money) {
            this.bettingMoney = bettingMoney.addMoney(money);
    }
}

public class BettingMoney {
    private final int bettingMoney;

    public BettingMoney(final int bettingMoney) {
        validatePositiveBettingMoney(bettingMoney);
        this.bettingMoney = bettingMoney;
    }

    public BettingMoney addMoney(final int money){
            return new BettingMoney(bettingMoney + money);
    }

    private void validatePositiveBettingMoney(int bettingMoney) {
       if (bettingMoney <= 0) {
           throw new IllegalArgumentException(String.format(NOT_POSITIVE_MONEY_EXCEPTION_MESSAGE, bettingMoney));
        }
    }
} 

원시값으로 도메인의 의미를 나타내면 도메인을 사용하는 곳에서 믿고 사용할 수 없을거에요(유효성, 동등성, 불변을 사용하는 곳에서 관리해야 하기 때문).

결국 원시값 포장을 통해 사용하려는 도메인의 의미를 더 정확하게 드러낼 수 있게 됐어요.

 

그럼 원시값 포장이랑 VO는 같은거네요?

아니요. 이부분이 정말 헷갈리는 부분이라 생각해요.

저는 위의 예제에서 윈시값 포장을 하며 VO로 만들었어요.

즉. 원시값 포장과 동시에 VO로 만들 순 있지만, 원시값 포장이 VO다 라고는 할 수 없어요.

(원시값 포장을 하고 불변이 아니길 원할 수도 있으니까요)

VO가 헷갈리는 분은 아래 포스팅을 참고해주세요

https://livenow14.tistory.com/18

 

아직 설명이 부족해요

아래는 원시값을 포장했고, vo로 만들었어요.

public class BettingMoney {
    private final int bettingMoney;

    public BettingMoney(final int bettingMoney) {
        validatePositiveBettingMoney(bettingMoney);
        this.bettingMoney = bettingMoney;
    }
} 

아래는 원시값을 포장했지만, vo는 아니에요.

public class BettingMoney {
    private int bettingMoney;

    public BettingMoney(final int bettingMoney) {
        validatePositiveBettingMoney(bettingMoney);
        this.bettingMoney = bettingMoney;
    }

    public void setMoney(int moneey){
         this.bettingMoney = money;
    }
} 

아래는 BigDecimal을 포장했고, vo로 만들었어요.

public class BettingMoney {
    private final BigDeciaml bettingMoney;

    public BettingMoney(final BigDeciaml bettingMoney) {
        validatePositiveBettingMoney(bettingMoney);
        this.bettingMoney = bettingMoney;
    }
} 

아래는 BigDecimal을 포장했지만, vo는 아니에요.

public class BettingMoney {
    private BigDeciaml bettingMoney;

    public BettingMoney(final BigDeciaml bettingMoney) {
        validatePositiveBettingMoney(bettingMoney);
        this.bettingMoney = bettingMoney;
    }

    public void setMoney(BigDecimal moneey){
         this.bettingMoney = money;
    }
} 

즉, 원시값 포장은 말그대로 primitive type을 포장했다는 것이에요.

(BigDeciaml은 BigDecimal 포장이지 원시값 포장이 아니에요.)

 

결론은,

원시값 포장

원시 유형의 값(변수명)을 이용해 의미를 나타내지 않고, 의미있는 객체로 포장한다는 개념

VO(값 객체)

  1. Immutability(불변성) - 수정자가(setter) 없다
  2. value equality(값 동등성) - 내부 값 동등성 검사
  3. self validation(자가 유효성 검사) - 생성자에서 validate

댓글