본문 바로가기
Back-End

방어적 복사

by 코젼 2025. 5. 15.
728x90
반응형

방어적 복사(Defensive Copy) 는 원본과의 참조를 끊은 복사본을 만들어 사용하는 방식이며, 원본의 변경에 의한 예상치 못한 사이드 이펙트를 방지하여 안전한 코드를 만들 수 있는데 도움이 됩니다.

방어적 복사는 2가지 시점이 존재하는데요. 생성자의 인자로 받은 객체의 복사본을 만들어 내부 필드를 초기화하거나, getter 메서드에서 객체를 반환할 때, 복사본을 만들어 반환할 수 있습니다. 만약 컬렉션 자료구조를 반환하는 경우라면 자바의 Unmodifiable Collection을 사용하여, 외부에서 Collection에 대해 조회만 할 수 있도록 강제할 수 있습니다. 자바에서 Unmodifiable Collection은 set(), add(), addAll() 처럼 컬렉션에 요소를 추가하거나 변경하는 메서드를 사용하는 경우, 예외를 발생합니다.

다음 코드에서 발생할 수 있는 문제점

public class Lotto {

  private final List<LottoNumber> numbers;

  public Lotto(List<LottoNumber> numbers) {
      validateSize(numbers);
      this.numbers = new ArrayList<>(numbers);  // 방어적 복사
  }
}

위 코드는 두 가지 문제점이 발생할 수 있습니다.

첫 번째는 생성자의 파라미터로 주어진 LottoNumber 리스트의 각 요소가 외부에서 변경될 수 있는 가능성이 존재합니다. 이러한 문제가 발생하는 이유는 방어적 복사가 깊은 복사가 아니기 때문입니다. 가령, 외부에서 다음과 같은 코드를 작성할 수 있습니다.

Lotto lotto = new Lotto(numbers);
numbers.get(0).changeNumber(1);

이 문제를 해결하기 위해서는 생성자의 파라미터에 Integer 리스트를 입력받거나, 방어적 복사 수행 시 내부 객체까지 깊은 복사를 수행할 수 있습니다.

또한 위 코드는 검증을 수행하는 시점에 외부에서 컬렉션이 변경이 발생할 수 있는 가능성이 존재합니다. 예를 들어, validateSize 메서드를 통과하고 방어적 복사를 수행하기 전에 외부에서 numbers에 값을 추가하는 경우, 검증은 성공했지만 객체의 값은 유효하지 않을 수 있습니다. 이 잠재적인 문제를 해결하기 위해서는 방어적 복사가 검증이 수행되기 이전에 이루어져야 합니다.

추가 학습 자료

728x90
반응형

'Back-End' 카테고리의 다른 글

Call By Value, Call By Reference  (2) 2025.05.14
교착상태  (0) 2025.05.13
Redis 가 싱글 스레드로 만들어진 이유  (0) 2025.05.12
응집도와 결합도  (2) 2025.05.09
NAT(Network Address Translaction)  (0) 2025.05.02

댓글