불변 객체

공병주(Chris)·2022년 3월 17일
0

Java를 탄탄히

목록 보기
6/9

DTO를 적용한 것에 대한 구구에게 이런 코멘트를 받았다.(나 말고도 똑같은 코멘트를 받은 크루들이 많더라..)

DTO가 필요한 경우는 아래 두가지가 있다고 생각한다.

  • 도메인에 상태를 변경할 수 있는 메소드가 열려있을 때 (가변 객체)
  • 노출시키지 않아도 되는 정보, 혹은 감춰야 하는 정보가 있을 때

첫번째 이유 때문에 이번 미션에서 DTO를 적용했다. 그런데 네오의 강의를 들으니 DTO를 적용하지 않고, 객체를 불변으로 만들면 DTO를 적용하지 않아도 된다는 생각이 들었다.

불변 객체

객체 지향 프로그래밍에 있어서 불변객체(immutable object)는 생성 후 그 상태를 바꿀 수 없는 객체를 말한다. - 위키피디아 불변객체-

public class Car {
    private final String name;
    private int distance;

    public Car(final String name, final int distance) {
        this.name = name;
        this.distance = distance;
    }

    public void move(final int movementValue) {
        distace += movementValue;
    }
}

위의 객체는 move가 distance의 상태를 변경할 수 있기 때문에 가변 객체이다.

public class Car {
    private final String name;
    private final int distance;

    public Car(final String name, final int distance) {
        this.name = name;
        this.distance = distance;
    }

    public Car move(final int movementValue) {
        return new Car(name, distance + movementValue);
    }
}

반면, 위의 객체는 객체의 상태를 변경할 수 없다. move 메소드를 호출하면 distance 값을 변경하는 것이 아닌 자신의 값을 기반으로 새로운 객체를 반환한다.

public class Car {
    private final CarName name;
    private final Distance distance;
    
    private Car(final CarName name, final Distance distance) {
    	this.name = name;
        this.distance = distance;
    }

    public Car(final String name, final int distance) {
    	super(new CarName(name), new Distance(distance));
    }
   

    public Car move(final int movementValue) {
        return new Car(name, distance.increaseBy(movementValue));
    }
}
public class Distance {
	private final int value;
    
    public Distance(final int value) {
    	this.value = value;
    }
    
    public Distance increaseBy(final int increasingValue) {
    	return new Distance(value + increasingValue);
    }
}

위와 같이 객체의 필드가 원시 타입이 아닌 참조 타입이라면 해당 객체도 불변으로 만들어 줘야 한다.

public class View {
    public void showDistance(final List<Car> cars) {
        // cars.forEach(car -> car.move(100_000)); 악행
        
        for (Car car : cars) {
            System.out.println(car.getDistance());
        }
    }
}

누가 위와 같은 악행을 범해도 기존 객체들의 상태가 바뀌는 것이 아니기 때문에 객체를 안전하게 보호할 수 있다.

비용 문제

그렇다면 위의 move 메소드를 호출 할 때 마다, 객체들이 생성되는 것이기 때문에 비용에 대한 걱정이 있을 수도 있다.
하지만, 지금 단계에선 아직 엄청 많은 객체를 생성할 일이 없고
오라클에서 gc를 믿고 사용하라고 한 만큼, 위의 비용 문제는 다시 생각해보도록 하자~!

profile
self-motivation

2개의 댓글

comment-user-thumbnail
2022년 3월 17일

혹시 그렇다면 이번 미션에서 뷰로 넘기게 되는 모든 객체를 불변 객체로 만들어 주셨나요??

1개의 답글