VO 불변객체

ezi·2023년 12월 27일
0
@Getter
@NoArgsConstructor
@Embeddable
public class PostProductPosition {

    @Column(precision = 4, scale = 3)
    private BigDecimal positionY;

    @Column(precision = 4, scale = 3)
    private BigDecimal positionX;

    @Override
    public boolean equals(Object o)
    {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PostProductPosition that = (PostProductPosition) o;
        return
                that.getPositionY().doubleValue() == this.getPositionY().doubleValue() &&
                that.getPositionX().doubleValue() == this.getPositionX().doubleValue();
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(positionY.doubleValue(), positionX.doubleValue());
    }

    private static boolean isInRange(BigDecimal value)
    {
        return (value.compareTo(BigDecimal.ZERO) > 0 && value.compareTo(BigDecimal.ONE) < 0);
    }

    private PostProductPosition(BigDecimal positionY, BigDecimal positionX)
    {
        if (!isInRange(positionY) || !isInRange(positionX))
        {
            throw new ApiException(ErrorCode.NOT_FOUND_POST);
        }

        this.positionY = positionY;
        this.positionX = positionX;
    }

    public static PostProductPosition of(BigDecimal positionY, BigDecimal positionX)
    {
        return new PostProductPosition(positionY, positionX);
    }
}

임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험

대신, 값(인스턴스)를 복사해서 사용해야 한다
항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수 있다

문제는 임베디드 타입처럼 직접 정의한 값 타입은 자바의 기본 타입이 아니라객체타입 이다.
자바 기본 타입에 값을 대입하면 값을 복사하지만,
객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없다.(공유참조)

객체 타입을 수정할 수 없게 만들면 부작용 원천 차단
값 타입은 불변객체(생성 시점 이후 절대 값을 변경할 수 없는 객체)로 설계해야 한다.

public static PostProductPosition of(BigDecimal positionY, BigDecimal positionX)
   {
       return new PostProductPosition(positionY, positionX);

VO는 인스턴스를 공유하기 때문에 나중에 값을 변경하면,
이전의 값도 변경되는 side effect가 발생

이를 방지하기 위해 setter를 사용하지 않고 생성자로만 값을 설정

하지만 값을 변경하고 싶을 땐?
변경할 값을 new 만들고, 이를 다시 통으로 끼워넣는 방법으로 대체한다


값 타입의 비교

값 타입 : 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야 함

  • 동일성 비교 : 인스턴스의 참조 값을 비교, == 사용
  • 동등성 비교 : 인스턴스의 값을 비교, equals() 사용

== 자체가 참조 값을 비교

값 타입은 a.equals(b)를 사용해서 동등성 비교를 해야한다
값 타입의 equals() 메소드를 적절하게 재정의하여 사용

equals의 기본이 == 비교

[override - equals, hashcode]

profile
차곡차곡

0개의 댓글