반응형

 setter나 getter는 엄청나게 쓰는 메서드들이기도 합니다. 그런데, 문득 setter는 왜 사용을 지양해야 한다고 할까? 에 대해서 곰곰히 생각해 보게 되었습니다. 사실, 이 질문에 대해서, 명확하게 떨어질 만한 답을 찾지 못하였습니다. 대신에, 외부에서 세터 를 호출해서, 변경이 되면 위험한 속성들에 대해서 다시 생각해 보게 되었습니다. 그에 대한 답 부터 해 보도록 하겠습니다.

 


 setter는 객체의 속성을 변경하는 메서드입니다. 예를 들자면 Dog라는 모델이 age와 이름을 가지고 있을 때, setName은 이름을 바꿔줄 때 쓰고, setAge는 나이를 바꿔줄 때 쓰입니다. 굳이 이들의 존재에 대해서 잘 모르더라도, Collections를 보시면 쉽게 찾을 수 있습니다. 예를 하나 들어보겠습니다.

 

 

 AbstractList에는 get과 set이 있습니다. 이들은 각각 x번째 요소를 리턴하고, x번째 요소의 값을 설정하는 메소드입니다.

 

 

 그리고 ArrayList는 AbstractList를 상속한 것이니, get, set 두 메서드가 있을 겁니다.

 

 

 이들은, element 데이터의 x번째 값을 가지고 오거나, 그 값을 바꿉니다. 예를 들자면, get(2)를 하면, 7을 가져올 겁니다.

 

 

 아니면 2번째에 있는 원소의 값을 15로 바꿀 수도 있을 겁니다.

 

 

 생각해 보면, List의 x번째 원소는 가져와도 되고, 변경할 수도 있는 속성입니다. 직관적으로는 그럴 수 있겠네요. 그런데, 사실 잘 와닿지는 않습니다. 그러니 하나의 예를 들어보도록 하겠습니다. 그걸 보시고, ArrayList 클래스에 setElementData 같은 건 왜 없을지 생각해 보시는 것도 도움이 되실 듯 싶습니다.

 


 ArrayList 클래스의 필드들을 보면 size라는 것이 있음을 알 수 있습니다. 신기하게도 이것은 getter 역할을 하는 size는 있습니다. 그런데, 두 눈을 씻고 찾아봐도 size를 설정하는 세터는 없음을 알 수 있습니다.

 

 

 왜 그럴까요? 먼저 size가 어디에 물리는 지 생각해 보겠습니다. rangeCheck 메소드에서 씁니다. 이것이 호출되는 메서드 중에 get도 있음을 확인할 수 있습니다.

 

 

 그리고 size는 add 메소드에서도 씁니다. 이것은 ArrayList의 끝에 원소를 추가하는 메서드입니다. size를 Set하는 세터가 하나 들어왔다고 가정해 보겠습니다.

 

 그리고 바깥에서 size를 2로 설정했다고 해 보겠습니다. 그 다음에, add(7)이 호출되었다고 해 보겠습니다. 우리의 기대는 4 뒤에 5가 추가되는 것일 겁니다. 그런데, 바깥에서 size가 2로 변경이 되었기 때문에, 15가 있던 자리에 7이 추가되어 버립니다.

 

 

 15는 어디로 갔나요? 덮어 씌워져 버렸습니다. size가 어딘가에서 2로 변경이 되어서, add를 호출한 결과, 15가 없어져 버렸습니다. 저는 3번째 원소였던 15가 삭제되기를 원하지 않았습니다. 단지, 저는 7만 추가되기를 기대했습니다. 그런데, 바깥에서 size를 함부로 바꿔버려서, 의도치 않게 15가 없어졌습니다. null 처리도 안 되어서, 메모리 릭 문제가 발생할 수도 있고요. 잘 생각해 보면 이펙티브 자바 3판의 코드 7-1하고 유사한 상황이 벌어짐을 알 수 있어요.

 

 이 상황 하나만 보았을 때, size는 외부에서 함부로 바뀌어서는 안 되는 속성임을 알 수 있습니다.

 

 

 그런데, 내부에서는 바뀐다고 할 수 있습니다. 내부에서 remove나 add를 하면 size가 바뀌는 것은 자연스러운 현상입니다.

 

 

 예를 들어 2번째 원소를 remove 한다고 생각해 보겠습니다. 그러면, 5를 제거하고 7을 앞으로 당길 겁니다.

 

 

 그 다음에 setter를 3으로 셋팅하고 뒤에 있는 7에는 null을 셋팅합니다.

 

 

 중요한 것은 이 일련의 과정은 remove를 하는 과정에서 일어났지, 외부에서 일어나지 않았다는 것입니다. 즉, 외부에서 size를 변경시키지도 말아야 할 것이고, 바깥에서 setting을 할 필요가 없습니다. 함부로 바꾸면 자료 구조가 망가져서 의도치 않는 동작을 할 수 있기 때문입니다. 굳이 risk를 감당할 이유는 없습니다. size를 외부에서 set할 필요가 없습니다. getter는 있습니다.

 

 

 이렇게 ArrayList의 size를 조회해서 쓰곤 합니다. 이는 size라는 속성 값을 가져오는 것은 그리 큰 상관이 없기 때문입니다. 순회할 때 많이 쓰이기도 하고요. 생각해 보면, dog도 동물 등록 번호는 함부로 바꾸면 안 되지만, 조회할 수는 있습니다. 누군가 조회해서 개의 주인을 찾아 줄 수도 있는 것이니, 나름의 쓰임새는 있습니다. 속성값을 얻어와서 쓸 데가 있기에, dog 클래스를 만든다면, 등록 번호 는 getter로 풀 수 있을 겁니다. 대신 외부에서 (주인이 직접) 동물 등록 번호를 set할 필요는 없으니, 굳이 setter를 넣을 필요는 없어 보입니다.

 

 정리하면, 외부에서 바꿔야 할 필요가 없는 데 굳이 setter를 써서 외부에 나 바꿔주세요. 할 필요가 없다는 것을 길게 풀어서 이야기 한 셈입니다. 

반응형

댓글을 달아 주세요

  1. IT 알려주는 은행원

    오 글 잘읽었습니다.
    실제 실무에서도 setter 사용은 최대한 지양하고 필요한 곳에서만 쓰는 걸 권장하더라구요.