14장: 일관성 있는 협력
변경을 분리하고 캡슐화하기
유사한 요구사항에 대해 각 협력이 서로 다른 패턴으로 구현되어 있다면 전체적인 설계의 일관성이 무너지고 비용이 증가한다.
유사한 기능을 구현하기 위해 일관성 있는 유사한 협력 패턴을 사용하면 시스템을 이해하고 확장하기 위해 요구되는 정신적인 부담을 크게 줄일 수 있다.
일관성 있는 설계를 만드려면 다양한 설계 경험을 익히고 널리 알려진 디자인 패턴을 학습하여 적용해보는 것이 필요하다.
늘 강조해왔듯, 변하는 개념과 변하지 않는 개념을 분리하고 변하는 개념은 캡슐화해야 한다. 여기서 캡슐화란 단순히 데이터를 감추는 것이 아니라 소프트웨어 안에서 변할 수 있는 모든 ‘개념’을 감추는 것이다.
캡슐화에는 클래스 내부 데이터를 캡슐화하는 데이터 캡슐화, 클래스의 내부 행동을 캡슐화하는 메서드 캡슐화, 합성을 사용해 객체를 캡슐화하는 객체 캡슐화, 실행 시점에 어떤 객체가 올 지 확인하도록 하는 서브타입 캡슐화가 존재한다.
서브타입 캡슐화와 객체 캡슐화는 다음과 같은 순서로 적용할 수 있다.
변하는 부분을 분리한 후 공통적인 행동을 추상 클래스/인터페이스로 정의하고 이를 상속받도록 한다.
변하지 않는 부분에 타입 계층을 합성(composite)하여 추상화에 의존하게 만든다.
변경의 이유에 따라 캡슐화할 수 있는 다양한 방법을 디자인 패턴에서 제시하므로 공부해보는 게 좋다.
다형성은 조건 로직을 객체 사이의 이동으로 바꾸기 위해 객체지향이 제공하는 설계 기법이다.
협력 패턴 구현하기
요구사항
여러가지 통화 요금 책정 방식이 존재할 수 있다.
아래는 그 중 한 방식인 시간대별 방식을 그림으로 나타낸 것이다. 1월1일 0시부터 1월3일 24시까지 통화가 이뤄졌고, 이 통화 내역을 시간대별로 분리하여 각각 다른 요금을 부과해야 한다.
설계
모든 작업을 객체의 책임으로 생각하고, 아래와 같이 객체를 설계한다.
BasicRatePolicy
사용자로부터 통화 목록이 담긴 핸드폰을 전달받으면 해당 핸드폰의 통화 요금을 반환한다.
FeeRule
시간대별로 분리된 통화 내역을 기반으로 가격을 계산한다.
FeeCondition
적용 조건을 표현하는 인터페이스
통화 내역을 전달받고 적용 조건을 만족하는 기간만 잘라 DateTimeInterval의 List로 반환하는 메서드가 있다.
FeePerDuration
특정 기간만큼의 통화 요금을 계산해 반환한다.
구현
BasicRatePolicy
하나의 통화 기록 당 통화 내역을 분리해 각각 요금을 계산하여 전체 요금을 반환하도록 한다.
FeeCondition
하나의 통화 내역을 전달받고 적용 조건을 만족하는 기간만 잘라 DateTimeInterval의 List로 반환한다.
시간대별 정책, 요일별 정책, 구간별 정책 등이 이 인터페이스를 구현하는 방식으로 표현될 것이다.
FeeRule
하나의 통화 내역을 구간별로 잘라 적용 조건에 따른 요금을 계산하여 반환한다.
FeePerDuration
얼마동안 통화할경우 얼마만큼의 요금이 나올 지 정의하여
요금 부과 정책 구현
FeeCondition을 구현하여 요금 부과 정책 클래스를 만든다.
아래는 시간대별 정책의 적용 조건을 구현하는 클래스로, 시작시간과 종료시간을 담아두고 통화 내역이 입력되면 시작시간과 종료시간에 해당하는 구간만 잘라내 반환한다.
아래는 구간별 정책의 적용 조건을 구현하는 클래스로, 특정 구간을 담아두고 통화 내역이 입력되면 구간에 만족하는 통화 기록 조각을 반환한다.
개념적 무결성을 무너뜨리는 것보다는 약간의 부조화를 수용하는 편이 더 낫다.
개념적 무결성: 일관성과 유사한 의미로, 시스템이 일관성 있는 몇 개의 협력 패턴으로 구성된다면 이해, 수정, 확장에 필요한 노력과 시간을 아낄 수 있다. 좋은 기능들이 서로 독립적이고 조화되지 못한 아이디어들을 담고 있는 시스템보다는 여러가지 다양한 기능이나 갱신된 내용은 비록 빠졌더라도 하나로 통합된 설계 패턴을 반영하는 시스템이 훨씬 좋다.
협력은 고정된 것이 아니다. 만약 현재의 협력 패턴이 변경을 수용하기 어렵다면 변경의 방향에 맞춰 최선의 협력 패턴을 만들도록 리팩토링해야 한다.
유사한 기능에 대한 변경이 지속적으로 발생하고 있다면 변경을 캡슐화할 수 있는 적절한 추상화를 찾아 반복적으로 적용할 수 있는 협력 구조를 도출하고, 이 추상화에 변하지 않는 공통적인 책임을 할당해야 한다.
Last updated