진짜 개발자
본문 바로가기

Application Knowhow/Common

ApplicationKnowhow - 불변객체란? (Immutable Object의 장점)

728x90
불변객체

 

이번 시간에는 불변객체에 대하 알아보도록 하겠습니다.

 

 

불변객체(Immutable Object)란?

불변객체란 한번 객체가 생성되면, 변하지 않는 객체를 의미합니다. Java의 대표적인 불변객체는 String이 있습니다.

 

 

불변객체와 불변객체가 아닌 것

불변객체

위의 객체는 불변객체입니다. 필드의 접근 제한자는 private이며, final 선언자를 통해 변수를 변경할 수 없도록 제한했습니다. (final 선언자가 부여된 필드의 경우, 생성자에서 최초 1회 초기화가 가능합니다.)

 

 

불변객체가 아닌 것들

아래의 객체들은 모두 불변객체가 아닙니다.

위의 객체의 경우 필드의 접근제한자가 public이기 때문에, 외부의 변경으로부터 자유롭지 못합니다.

 

위의 객체의 경우 setter메소드를 통해 accountNum을 변경할 수 있습니다.

 

 

 

 

왜 불변객체를 만들까?

불변객체에 대해 알고나면, 가장 먼저드는 생각이 있습니다. 왜 불변객체를 만들까?.. , 웹 서핑을 해보면, 아래와 같은 이유들을 자주 볼 수 있습니다.

  • 다중 스레드 환경에서 안전하다.
  • 방어적 복사본을 만들 필요가 없다.
  • 사이드 이펙트가 발생할 확률이 적다.

 

제 얕은 식견으로는, 정말 이해가 가질 않았습니다. 하지만, 조금만 고민해본다면, 그다지 어려운 얘기도 아니었습니다. 바로 예제를 통해 설명을 드리겠습니다.

 

 

 

 

불변객체를 사용하지 않은 경우

왜 사용하는지를 알기 위해서, 반대로 사용하지 않은 경우의 불편한 점을 알아보면 조금 더 와닿을 수 있습니다.

 

위의 People불변객체일까요? 아쉽지만, 불변객체가 아닙니다. PeopleInformation 참조변수가, final로 선언되었고, setter 메소드 역시 존재하지 않음에도 왜 불변객체가 아닐까요? 이유는 참조변수인 PeopleInformation 에 있습니다. People 객체가 포함하고 있는, PeopleInformation 객체가 불변객체가 아니기 때문입니다.

 

 

문제점

그렇다면 어떤 문제점을 안고 있을까요? People 객체의 문제점을 살펴보도록 합시다.

 

우선, PeopleInformation 객체에는 galid라는 이름과, 20이라는 나이가 부여되었고, p1객체의 인자로 전달했습니다.

 

이 후, p2 객체에서 PeopleInformation 객체를 재사용하기 위해, setter메소드를 이용해, 원하는 데이터로 변경한 뒤, p2의 인자로 전달했습니다.

 

결과는 어떨까요? p1객체는 변화를 원하지 않았음에도 데이터가 변경되었습니다. 바로 이런 문제점으로 인해, 불변객체는 데이터를 확신할 수 없게 됩니다.

 

그림으로 다시한번 살펴보겠습니다. p1PeopleInformation("galid", 20) 객체를 참조합니다.

 

p2가 나타나 p1이 사용하는 객체를 재사용하기 위해, 원하는 대로 데이터를 변경합니다. 이때, p1은 같은 객체를 참조하고 있기 때문에, 데이터가 같이 변경됩니다.

 

 

 

방어적 복사본

그렇다면, 인터넷에 그토록 쓰여있는, 방어적 복사본이란 무엇일까요? 바로 위 PeopleInformation 객체처럼, 다른 객체에서 고루 사용될 가능성이 있는 객체가 변경될 수 있기 때문에, 객체 내부적으로 새로운 객체를 만들어 반환하도록 만든 코드를 의미합니다.

 

예제를 통해 알아보도록 합시다.

 

위의 Money 클래스는 방어적 복사본을 통해 객체의 변경을 방지한, 클래스의 예입니다. 한번 사용해보죠,

 

m1이 100을 가지고 생성이 되었습니다. m2m1의 값에 300을 더한 값을 자신의 value로 사용하려고 하네요, 저런, 또 m1의 값이 변경되지 않을까요?..

 

아닙니다, m1의 값은 유지가 됩니다. 바로 방어적 복사본을 이용했기 때문이죠, Money 클래스는 이 클래스를 통해 생성되는 객체가 다시 이용될 것을 미리 예측하고, addMoney() 메소드의 결과로 새로운 객체를 생성하여 전달했기 때문입니다.

 

 

 

결론

불변객체는 위와같이 방어적 복사본을 만들어야하는 수고를 덜어주며, 다중스레드 환경에서도 안전합니다.