middlefitting

getter, setter 그리고 캡슐화 본문

JAVA

getter, setter 그리고 캡슐화

middlefitting 2023. 5. 2. 05:18

이 글은 객체지향 프로그래밍 캡슐화 개념을 모르시거나 모호하다고 느끼는 분들을 위한 글입니다. 다음과 같은 내용으로 시작합니다.

 

우리는 OOP 4대 원칙인 캡슐화를 준수하기 위해, 흔히 멤버 변수를 접근 제어자를 통해 숨기고 getter, setter 메서드를 통해 우회해서 접근 및 수정하도록 합니다.

 

근데 이 부분에서 우리는 다음과 같은 의문을 가지게 됩니다.

 

접근 제어자 걸어도 getter, setter 선언하면 public으로 선언하는 것과 캡슐화 측면에서 무슨 차이가 있는걸까?

 

그말이 그말인것 같은데 무슨 차이가 있으며, getter setter가 왜 캡슐화를 위해 사용된다는 것인지 의문을 품게 되는 것입니다.

 

결론을 이야기 하자면 차이가 없습니다. 즉 캡슐화를 위배한다는 것은 다를바가 없는 것이죠. 

 

물론 setter 메서드 내에서 제약조건을 걸 수 있으니 안정성 측면에서 좋은 점은 있다고 말할 수 있겠습니다만, 캡슐화를 위배한다는 점은 달라지지 않습니다. 그 점은 캡슐화의 정의를 보면 알 수 있습니다.

 

 

캡슐화란 ?


캡슐화의 간단한 정의는 객체의 내부를 외부로부터 숨기는 것을 말합니다.

 

우선 인스턴스 변수는 내부에 속할까요. 그렇습니다. 접근제어자를 거는 것만 봐도 뭔가 숨기려고 하고 있죠.

 

우선 이 부분만 고려해도 getter setter는 캡슐화를 위배한다는 판단이 들기 시작합니다. 결국 접근제어자를 통해 기껏 숨긴 인스턴스 변수들을 메서드라는 수단을 통해 외부로 노출시키고 있기 때문입니다.

 

 

gettter setter는 사용하면 안되는가


그러면 해당 메서드들은 사용하면 안되는 것일까요.

 

지양해야 하는 것이 맞습니다. getter와 setter를 신나게 사용하는 것은 OOP 4대원칙을 신나게 위배하는 것과 같은 말이 되니까요.

 

물론 그렇다고 절대 사용하면 안되는 것은 아닙니다. 예를 들어 DTO와 같은 데이터 전달 객체는 데이터의 성격을 가지는데요, 객체이지만 데이터의 성격을 가지는 것입니다. 여기서는 내부에 있는 데이터를 꺼내서 사용해야 하니 getter 메서드를 정의해야 할 것입니다.

 

이런 특수한 경우가 있으니 잘 판단해서 사용하되, 남용하지 않도록 하면 됩니다.

 

 

캡슐화의 진정한 의미


다시 돌아와서 캡슐화의 진정한 의미에 대해 다시 알아보겠습니다.

 

오브젝트의 저자이신 조영호님의 말을 인용하였습니다.

 

캡슐화에서 내부 속성을 감추는 것은 캡슐화의 한 종류일 뿐, 변경될 수 있는 어떤 것이라도 감추는 것을 의미한다.

 

변경될 수 있는 어떤 것이 어떤 것인지 판단이 서지 않으면, 변경되지 말아야 하는 것만 기억하시면 됩니다.

 

외부에 노출된 인터페이스는 변경되면 안됩니다. 인터페이스가 변경되는 것은 결합도 이런걸 떠나서 수많은 코드가 변경될 수밖에 없다는 것은 저명합니다. 예를 들어 import 해서 사용하는 자바 패키지의 어떤 인터페이스가 변경되는 것을 상상해 보면 끔찍하니 그런 일은 생기면 안된다는 것을 충분히 이해할 수 있습니다.

 

이것을 보면 다시 한번 getter setter를 지양해야 한다는 것을 새길 수 있습니다.

 

인터페이스는 변경되면 안되는데 해당 메서드들은 객체 상태에 의존적입니다. 특정 인스턴스 멤버변수에 매우 의존하고 있죠. 

 

그런데 상태는 변경될 수 있습니다. 리팩토링을 수행하며 자료형을 바꿀 수도 있고, 상태값 자체가 바뀌어야 하는 경우도 충분히 발생할 것입니다. 그러면 getter setter 메서드가 사라지거나 변경되는 일로 자연스럽게 이어지고, 외부에 노출한 메서드가 변경되게 되니 해당 메서드를 참고하고 있는 수많은 클래스들이 영향을 받게 될 것입니다. 

 

자연스럽게 다음과 같은 문제들이 발생한다는 것을 파악할 수 있습니다.

1. getter setter 인터페이스가 불안정한 상태에 강력하게 의존한다는 아이러니한 일이 발생

2. 객체 상태를 드러내니 캡슐화 위반

3. 해당 메서드를 사용하는 외부 클래스들은 상태에 의존하는 것과 마찬가지니 결합도 상승

4. 해당 메서드를 사용하는 외부 클래스들이 상태가 바뀌면 덩달아 변경이 필요해지게 되니 응집도 약화

 

아주 다양한 문제들이 발생하게 되는데요, 캡슐화를 잘 지켜야겠다는 다짐을 할 수 있습니다.

 

 

좀 더 나은 설계


결론은 캡슐화를 잘 지켜야 유연한 설계를 할 수 있다는 것입니다.

 

getter setter를 통해 예시를 들었는데요, 이 둘은 인터페이스가 상태 변경에 따라 덩달아 변경된다는 문제점을 가지고 있었습니다.

 

객체의 내부구현은 언제든지 변경이 이루어질 수 있어야 합니다. 그리고 이를 위해서는 캡슐화가 잘 이루어져야 합니다.

 

객체는 외부와의 소통을 인터페이스로만 진행하여야 합니다. 그리고 그 인터페이스는 변경이 되게 설계하면 안됩니다.

 

getter setter의 가장 큰 문제점은 상태 변경에 따라 인터페이스 자체가 변경이 될 수 있다는 점이었습니다.

 

즉 인터페이스는 불안정한 객체 내부 상태와 관련없이 변하지 않아야 합니다. 단순히 getter setter에 국한된 내용이 아닙니다.

 

인터페이스를 변하지 않게 설계하여야 유연한 설계를 얻을 수 있습니다.

 

 

참고문헌


[ 오브젝트 ] 조영호

https://product.kyobobook.co.kr/detail/S000001766367

 

오브젝트 | 조영호 - 교보문고

오브젝트 | 역할, 책임, 협력을 향해 객체지향적으로 프로그래밍하라!객체지향으로 향하는 첫걸음은 클래스가 아니라 객체를 바라보는 것에서부터 시작한다. 객체지향으로 향하는 두번째 걸음

product.kyobobook.co.kr

 

'JAVA' 카테고리의 다른 글

세 가지 의미로 알아보는 JVM  (0) 2024.06.09
Java 메서드 오버라이딩에 관하여  (0) 2023.03.12
[OOP] Java 추상화 이해하기  (0) 2023.02.23
[OOP] 다형성이란 무엇일까  (0) 2023.02.21
[OOP] Java 상속에 관하여  (0) 2023.02.20