로버트 마틴이 말하는 소프트웨어 모듈이 가져야 하는 세가지 기능
앞서 구현한 프로그램의 경우, 첫번째 모듈의 목적을 달성했으나 변경 용이성과 코드 가독성을 만족시키지 못함
Theater 클래스의 enter 메서드가 하는 일
문제는 관람객과 판매원이 소극장의 통제를 받는 수동적인 존재라는 점
이해 가능한 코드: 그 동작이 우리의 예상에서 크게 벗어나지 않는 코드
이 코드는 우리의 예상에서 벗어나는 코드이기 때문에 코드를 읽는 사람과 의사소통을 할 수 없음
또한, 이 코드를 이해하기 위해 여러가지 세부적인 내용들을 한꺼번에 기억하고 있어야 한다는 문제도 갖고 있음
즉, 하나의 클래스나 메서드에서 너무 많은 세부사항을 다루기 때문에 코드를 작성하는 사람뿐만 아니라 코드를 읽고 이해하는 사람에게 큰 부담을 주게 됨
가장 심각한 문제는 Audience, TicketSeller를 변경할 경우 Theater도 함께 변경해야 하는 문제
관람객이 현금과 초대장을 보관하기 위해 항상 가방을 들고다닌다고 가정
Audience 클래스에서 Bag을 제거하고 Audience의 Bag에 직접 접근하는 Theater의 enter 메서드도 수정해야 함
이처럼, 세부적인 사실에 의존해 있는 구조라면 세부적인 사실 중 하나만 변경이 되더라도 해당 클래스 뿐만아니라 의존하는 다른 클래스들까지 변경해야 하는 번거로움이 발생
(다른 클래스가 Audience의 내부에 대해 더 많이 알면 알수록 Audience를 변경하기 까다로워짐)
객체 사이의 의존성(Dependency)와 관련된 문제
의존성이 변경에 대한 영향을 암시함
즉, 의존성은 어떤 객체가 변경될 때 그 객체에게 의존하는 다른 객체도 함께 변경될 수 있다는 사실이 포함되어 있음
애플리케이션 기능을 구현하는데 필요한 최소한의 의존성만 유지하고 불필요한 의존성을 제거해가는 것이 목표!
객체 사이의 의존성이 과한 경우를 가리켜 결합도(coupling)이 높다고 말함
반대로, 객체들이 합리적인 수준으로 의존할 경우 결합도가 낮다고 말할 수 있음
설계의 목표 - 객체 사이의 결합도를 낮춰 변경 용이한 설계를 만드는 것
로버트 마틴이 이야기한 세가지 목적중 두가지 조건을 만족시키기 위해 개선해야 함
우리의 예상을 벗어나는 코드
관람객이 스스로 가방안의 현금과 초대장을 처리하고 판매원이 스스로 매표소의 티켓과 판매 요금을 다루게 한다면 문제 해결 가능 (즉, 판매원과 관람객을 자율적인 존재로 만들자)
설계 변경의 어려움: Theater에서 Audience, TicketSeller이외에도 Audience 내의 Bag과 TicketSeller가 근무하는 TicketOffice까지 마음대로 접근하기 때문
해결 방법: Audience와 TicketSeller가 직접 Bag, TicketOffice를 처리하는 자율적인 존재가 되도록 설계를 변경하는 것
Theater의 enter() -> TicketSeller의 sellTo()로 이동
TicketSeller에서 getTicketOffice() 메서드가 제거되어 더 이상 외부에서 ticketOffice 필드에 접근할 수 없게 됨
따라서 TicketSeller는 ticketOffice에서 티켓, 요금 관리를 스스로 수행하게 됨
이처럼 개념적이나 물리적으로 객체 내부의 세부적인 사항을 감추는 것을 캡슐화(encapsulation)이라고 함
캡슐화는 변경하기 쉬운 객체를 만드는 것이 목적
캡슐화를 통해 객체 내부로의 접근을 제한하면 객체 간의 결합도를 낮출 수 있으므로 설계를 쉽게 변경하게 됨
Audience와 TicketSeller는 자신이 갖고 있는 소지품을 스스로 관리하게 변경됨으로써 코드를 읽는 사람과의 의사소통이 개선되었음
더 중요한 것은 두 클래스의 내부를 개선하더라도 Theater를 함께 변경할 필요가 없어짐
객체 내부 상태를 캡슐화하고 객체 간에 오직 메시지를 통해서만 상호작용할 수 있도록 만드는 것
밀접하게 연관된 작업만 수행하고 연관성 없는 작업은 다른 객체에게 위임하는 객체를 가리켜 응집도(cohesion)이 높다고 말함
자신의 데이터를 스스로 처리하는 자율적인 객체를 만들면 결합도를 낮출 수 있으며 응집도도 높일 수 있음