# 모든 원시값과 문자열을 포장하라

Java에는 아래와 같은 기본형을 가지고 있다.

  • byte
  • short
  • int
  • long
  • float
  • double
  • boolean
  • char

모든 원시값과 문자열을 포장하라는 위와 같은 기본형을 사용하는 원시값문자열을 나타내는String을 그대로 사용하지 않고 의미있는 객체로 포장한다는 의미이다.

# 예시

위 설명으로는 와닿지 않기 때문에 간단한 예시를 작성하였다.

# Car

Car는 이름을 나타내는 name과 현재 위치를 나타내는 position을 가지고 있다. name에는 다양한 요구사항이 주어진다고 가정한다.

  • 자동차의 이름은 5자 이하이다.
  • 자동차의 이름은 null이 올 수 없다.
  • 자동차의 이름은 이 올 수 없다.
  • 자동차의 이름은 ``이 올 수 없다.

이러한 요구사항 만족을 위해서는 다양한 검증 코드를 사용해야 했다.

public class Car {
    private final String name;
    private int position;
    ...
    
    public Car(String name) {
        validateNull(name);
        validateEmpty(name);
        validateBlank(name);
        validateNameLength(name);
        this.name = name;
        this.position = 0;
        ...
    }

    private void validateNull(String name) {
        if (name == null) {
            throw new IllegalArgumentException();
        }
    }

    private void validateEmpty(String name) {
        if (name.isEmpty()) {
            throw new IllegalArgumentException();
        }
    }

    private void validateBlank(String name) {
        if (name.isBlank()) {
            throw new IllegalArgumentException();
        }
    }

    private void validateNameLength(String name) {
        if (name.length() > 5) {
            throw new IllegalArgumentException();
        }
    }
    ...
}

Car와 관련된 객체이지만 name에 대한 검증 책임이 대부분을 차지하고 있기 때문에 해당 객체의 책임을 이해하는데 어려움이 있다고 판단한다.

# 개선

위 코드는 private final String name객체로 포장하여 책임을 분리하여 개선할 수 있다.

# CarName

public class CarName {
    private final String name;

    public CarName(String name) {
        validateNull(name);
        validateEmpty(name);
        validateBlank(name);
        validateNameLength(name);
        this.name = name;
    }

    private void validateNull(String name) {
        if (name == null) {
            throw new IllegalArgumentException("이름은 null이 될 수 없습니다.");
        }
    }

    private void validateEmpty(String name) {
        if (name.isEmpty()) {
            throw new IllegalArgumentException("이름이 비어 있습니다.");
        }
    }

    private void validateBlank(String name) {
        if (name.isBlank()) {
            throw new IllegalArgumentException("이름은 공백이 될 수 없습니다.");
        }
    }

    private void validateNameLength(String name) {
        if (name.length() > 5) {
            throw new IllegalArgumentException("이름은 5자를 초과할 수 없습니다.");
        }
    }

    public String getName() {
        return name;
    }
}

# Car

public class Car {
    private final CarName name;
    private int position;
    private final MovingPolicy movingPolicy;

    public Car(String name, MovingPolicy movingPolicy) {
        this.name = new CarName(name);
        this.position = 0;
        this.movingPolicy = movingPolicy;
    }

    public void move() {
        if (movingPolicy.isMovable()) {
            position++;
        }
    }

    public String getName() {
        return name.getName();
    }

    public int getPosition() {
        return position;
    }
}

name에 대한 검증 책임을 모두 이전하였다. 이제 Car는 오직 이동에 대한 책임만을 가지고 있게 된다.

# 정리

정리하면 원시값과 문자열을 객체로 포장하여 좀 더 유의미한 객체로 표현하는 것이다.

CarName이라는 객체는 Java에서 기존에 제공되는 API가 아니다. 즉 주어진 요구사항에 맞춰 새롭게 문자열을 포장한 객체이다.

#우아한테크코스 #원시값 포장 #객체지향 생활체조
last updated: 2/17/2022, 8:24:56 PM