객체 지향의 특징은 아래와 같습니다.
이 중 캡슐화에 대해서 다루는 것이 이 포스팅의 목적입니다.
객체 지향 프로그래밍에서 기능과 특성의 모음을 "클래스"라는 "캡슐"에 넣어서 분류해서 넣는 것
캡슐화(encapsulation)라는 말을 처음 들었어도 이게 뭔가를 "캡슐에 넣는다" 라는 것 정도는 짐작이 가능하다.
이렇게 캡슐이라는 것을 볼 때 두가지 특징을 확인할 수가 있다.
이 때 무언가를 모은다는 개념은 앞선 포스팅에 해당하는 추상화와 비슷한 것을 알 수 있다. 다만 차이점은 아래와 같다.
다음과 같은 코드를 생각해보자.
class SinivelCap { // 콧물 처치용 캡슐
void take() {
System.out.println("콧물이 싹~ 납니다.");
}
}
class SneezeCap { // 재채기 처치용 캡슐
void take() {
System.out.println("재채기가 멎습니다.");
}
}
class SnuffleCap { // 코 막힘 처치용 캡슐
void take() {
System.out.println("코가 뻥 뚫립니다.");
}
}
다음 클래스들은 각각의 약을 나타내고 있다. 만약 여기서 약 복용 순서가 고정이 되어있다면 어떨까? 캡슐화가 아니라면 다음과 같이 표현될 것이다.
class BadEncapsulation {
public static void main(String[] args) {
ColdPatient suf = new ColdPatient();
// 콧물 캡슐 구매 후 복용
suf.takeSinivelCap(new SinivelCap());
// 재채기 캡슐 구매 후 복용
suf.takeSneezeCap(new SneezeCap());
// 코막힘 캡슐 구매 후 복용
suf.takeSnuffleCap(new SnuffleCap());
}
}
그런데 이를 여러 번을 사용해야 된다면 어떨까? 코드 길이가 증가하고 좀 더 복잡해질 것이다. 캡슐화는 따로 메소드를 만들어서 그것으로 접근하는 것을 통해 구현하게 된다. 무슨 말인지는 아래를 보면 된다.
class SinusCap {
SinivelCap siCap = new SinivelCap();
SneezeCap szCap = new SneezeCap();
SnuffleCap sfCap = new SnuffleCap();
void take() {
siCap.take(); szCap.take(); sfCap.take();
}
}
여기서는 void take()
를 만들어 이 메소드에 대한 접근을 통해 "약을 복용하는 것"을 구현할 수 있다. main()
에서는 저기 있는 take()
를 가져다만 쓰면 되는 것이다.
이 과정에서 관련 있는 것들 끼리 잘 뭉쳐져 있는 것을 확인할 수 있고 이를 우리가 응집도(cohesion)이 높다고 표현한다.
좋은 코드는 흔히 응집도(cohesion)은 높고 결합도(Coupling)은 낮아야 한다고 한다. 결합도는 다른 요소들에 의존적인 것을 말하는데, 응집도 높이는건 언급했으니 결합도 낮추는 것은 어떻게 해야할까?
바로 외부에서 함부로 내부 데이터에 접근해서 수정하지 않도록 하는 것이다. 즉, 은닉이 필요하다. 자바에서는 필드에 private
을 붙혀 자신 클래스만 접근하도록하고, 단지 생성자나 getter/setter
를 통해서만 값에 접근이 가능하도록 설계한다.
즉, 외부로 영향을 최소화하기위해 정보의 은닉을 포함하는 개념이 바로 캡슐화이다.