한 Position을 여러곳에서 사용하는 경우 버그가 생길 가능성이 높아진다.
(여기저기서 채용하기 때문에)
X
public void increase() {
value++;
}
O
public Position increase() {
return new Position(value + 1);
}
고민할거리
무조건 객체를 새로 생성해 리턴하는게 항상 좋을까?
위 코드의 문제점은 성능 문제가 있음.
객체를 항상 생성해서 리턴한다는 것은 메모리 사용량이 크다는 것을 의미한다.
record Car(
String name,
Position position
) {
private static final Map<String, Car> CACHE = new ConcurrentHashMap<>();
public static Car of(final String name, final Position position) {
return CACHE.computeIfAbsent(toKey(name, position), key -> new Car(key, position));
}
private static String toKey(final String name, final Position position) {
return name + position.value();
}
public Car forward() {
// Note: 움직일 때 마다 캐싱된 객체가 재활용된다. 하지만 캐싱된 객체가 많을수록 메모리 사용량이 증가한다.
return Car.of(name, position.increase());
}
}
of(정적 팩토링방식), computIfAbsent등 다음에 써보자
private static final int CACHE_MIN = 0;
private static final int CACHE_MAX = 5;
...
if (CACHE_MIN <= value && value <= CACHE_MAX) {
return CACHE.get(value);
}
return new PositionForEnhancedCache(value);
캐싱을 무조건 하는게 좋을까?
public void forward() {
position = position.increase();
}
가변객체 방식처럼 increase를 사용하는 모습
public Position increase() {
return new Position(value + 1);
}
위 방식을 다음 미션에 한번 적용해보자.
List<Car> getParticipants() {
// Note: 매번 새로운 리스트를 생성하여 성능상의 이슈가 발생할 수 있다.
return participants;
}
위 코드에서 List를 반환하면 외부에서 이를 수정해버릴 수 있다.
List<Car> getParticipants() {
// Note: 매번 새로운 리스트를 생성하여 성능상의 이슈가 발생할 수 있다.
(방어적 복사)
return new ArrayList<>(participants);
}
프로퍼티를 오픈하지 않고 단지 메시지만 받아 내부에서 처리하기
getParticipants 제거 및 add 등 함수단위로 관리하기