본문 바로가기

방법/객체지향프로그래밍

객체지향프로그래밍 (OOP) - 캡슐화

캡슐화(Encapsulation) - "서먹한 관계를 선사시켜드립니다~"

정의

  캡슐화란 무엇인가? 또 딱딱하게 정의해보자면, 객체의 속성과 행위를 하나로 묶어 실제 구현 내용을 은닉하는 것이다. 또 다시 말하자면, 추상화로 지정한 범위를 울타리로 감싸주는 것이라고도 할 수 있다. 

적당한 선을 지켜, 바른 관계를 만들어 주는 것이 캡슐화다.


왜?

다른 사람이 내 전화번호, 키, 몸무게, 심지어 성별까지 바꿀 수 있으면 어떨까? 기분이 나쁜 것은 기본이고, 내 정체성에 문제가 생기고, 마치 드라마 <뷰티 인사이드>의 주인공처럼 들쑥날쑥한 삶이 매우 피곤할 것이다(물론 주인공은 연애도 커리어도 성공하지만).객체도 마찬가지다. 다른 객체가 마음대로 자신을 조종하면, 반드시 문제가 발생하기 마련이다.

개인정보 보호는 철저히!

자! 이제 조금 더 자세히 캡슐화를 구현해야 하는 이유를 살펴보자.

  캡슐화를 구현한다면, 객체는 외부에 행위(method)만을 공개할 것이다. 그렇다면, 자연스럽게 속성(property)는 물론, 실제 구현 방법까지 내부에 보호되어 외부에서는 접근하지 못할 것이다. 이로써 객체의 속성을 접근(변경)할 수 있는 객체는 그 객체 자신만이 가능하게 되었다.

 

이는 언뜻 보면 "굳이?, 왜?"라는 생각이 들 수 있지만, 다시 한 번 생각해보자.

 각각 다른 곳에서 각각 다른 코드로 내 객체의 속성을 건드린다면 어떨까?

  1. 일단, 코드의 중복이 일어날 것이다. -> 코드 수정이 발생한다면 하나하나 찾아서 고쳐야 한다는 말이다. (ex. 속성의 형변형 이슈)
  2. 어디서나 내 속성을 건드릴 수 있다는 말은 책임소재가 애매해진다는 말이다. -> 에러가 발생했을 때 추적이 어려워진다.
  3. 개발자가 바뀌었을 때 건드릴 수 있다. -> 1,2번 이슈가 또 발생..

캡슐화를 적용한다면, 위 문제들을 해결할 수 있다!


어떻게?

JAVA는 접근제한자를 통해 캡슐화를 가능케 한다. (접근제한자에 대한 설명은 생략한다.)

// wrong way 
// 이거는 자료구조에 불과하다
public class Point {
	public double x; // 속성을 public으로 노출시킴
	public double y;
}

// right way
// 객체
// 이 인터페이스를 구현한 클래스는 내부 속성이 어떤 좌표계로 이뤄져 있는지 알 수 없다. 
// "추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있다"라는 진정한 객체
public interface Point {
	// 내부적으로 데카르트 좌표계로 쓸 지, 극 좌표계를 쓸 지는 내 맘이다. 

	double getX();
	double getY();
	void setCartesian(double x, double y); // 데카르트 좌표계
    
	double getR();
	double getTheta();
	void setPolar(double r, double theta); // 극 좌표계
}

 위 예제에서 보면, <wrong way>는 자료구조에 불과하다. 이는 모든 속성을 공개함으로 다른 객체들이 마음대로 만질 수 있게 된다. 이 말은 아까 말했던 문제들이 발생할 수 있다는 것이다.

※ 자료구조가 무조건 나쁜 것은 아니다. 자료구조는 Kotlin의 data class와 같이 DTO로 유용하게 쓰일 수도 있다.

 

 이에 반해 <right way>는 진정한 객체라고 할 수 있다. 일단 위 문제점들은 모두 해결되고, 이 객체를 사용하는 곳에서 Point의 속성을 가지고 일일이 계산할 필요가 없어진다!

 

위에서 볼 수 있듯, 캡슐화는 클래스화와 접근제한자를 통해 구현한다.

 클래스화: 속성과 행위를 (추상화를 통해) 묶는다.

 접근제한자: 접근 제한자를 통해 속성을 숨긴다. (행위도 숨길 수 있다.)

 

궁금증

 나는 캡슐화의 구현 방법을 처음 들었을 때, "잉? getter/setter가 있으면 결국 밖에서도 마음대로 쓸 수 있는 거 아닌가?"라고 생각했다. 실무에서도 그런 경우도 많기도 하고.. 

 

 일단, 불필요한 조회함수는 다 지워버리면 된다. 이렇게 하면 밖에서 마음대로 내 객체를 못 쓰지 않는가. (객체의 행위는 단순 get, set이 아니다. 객체의 속성을 이용한 행위가 진정한 객체의 행위이다)

 다른 경우에는, getter, setter 내부에 유효성 검사나 추가 로직을 넣는다. 이렇게 하면, 밖에서 변경할 수 있으나 나의 통제 아래에서만 변경이 가능하다.


  오늘은 캡슐화에 대해 알아보았다.

오늘 내용이 어려웠다면, (내 잘못일 수도 있지만) "추상화",  "접근제한자", "인터페이스", "getter/setter", "객체와 자료구조"에 대해 검색해보고 다시 보면 좋을 것 같다.

더 깊게 알아보고 싶다면 "느슨한 결합", "디미터 법칙"를 검색해보면 될 것 같다.