[테스트 주도 개발] 30장_디자인 패턴
TDD 에서 쓰일 수 있는 디자인 패턴들을 정리한다.
커맨트 패턴
간단한 메서드 호출보다 복잡한 형태의 계산 작업에 대한 호출이 필요하다면 어떻게 할까?
계산 작업에 대한 객체를 생성해서 이를 호출하면 된다. Runnable 인터페이스가 대표적인 예이다.
값 객체
공유되어야 하지만, identity (동일성) 은 중요하지 않을 때 겍체를 어떤식으로 설계할까?
객체가 생성될 때 객체의 상태를 설정한다. 그리고, 이 상태가 절대 변할 수 없도록 해라. 이 객체에 대해 수행되는 연산은 언제나 새로운 객체를 반환하게 만들어라.
별칭 문제란, 두 객체가 제 삼의 다른 객체에 대한 참조를 공유하는데, 한 객체가 공유 객체의 상태를 변화시키면, 다른 객체가 영향을 받는 문제이다. 해결하기 위한 방법으로,
- 의존하는 객체애 대한 참조를 외부로 알리지 않는 방법이다. 그 대신 객체에 대한 복사본을 제공한다. 이 방법의 문제는, 수행 시간이나 메모리 공간 측면에서 비효율적이다. 또한, 공유 객체의 상태 변화를 공유할 수 없다.
- 옵저버 패턴. 의존하는 객체에 자기를 등록해 놓고, 객체의 상태가 변하면 통지를 받는다. 이 방법의 문제는, 제어 흐름이 어렵고 의존성을 설정하고 제거하기 위한 로직이 지저분해진다.
- 객체를 덜 객체답게 취급. 객체는 시간의 흐름에 따라 변할 수 있는 상태를 가진다. 그런데, 이러한 특징을 제거해버려라. 이것이 값 객체이다.
모든 값 객체는 동등성을 구현해야한다. 만약,
- 계약을 표현하는 객체가 두 개가 있는데, 둘이 서로 같은 객체가 아니면 이 둘은 동등한것이 아니라 다른것이다.
- 하지만, 5프랑 짜리 동전 두개가 있는데, 이 동전들이 동일한 (identity) 동전인지는 중요하지 않다. 5프랑은 5프랑이다. 이들은 동등해야한다.(equality)
널 객체
객체의 특별한 상황은 어떻게 표현하나?
그 상황을 표현하는 새로운 객체를 만들어라. Java.io.File 에는 getSesurityManager() 의 반환값이 null 인지 항상 검사를 한다. 다른 방법은 새로운 클래스를 만드는 것이다.
1 | public static SecurityManager getSecurityManager(){ |
템플릿 메서드
작업 순서는 변하지 않지만, 각 작업 단위에 대한 미래의 개선 가능성을 열어두고 싶으면?
다른 메서드들을 호출하는 내용으로만 이루어진 메서드를 만들어라.
플러거블 객체
변이를 어떻게 표현?
명시적인 조건을 사용해라. 다음은 중복 조건문들이 정의된 코드이다.
1 | public class SelectionTool { |
해법으로, 다음과 같이 플러거블 객체인 SelectionMode 를 만들어라.
1 | public class SelectionTool { |
플러거블 셀렉터
인스턴스 별로 서로 다른 메서드가 동적으로 호출하게 하려면?
메서드의 이름을 저장하고 있다가 그 이름에 해당하는 메서드를 동적으로 호출해라. 다음과 같이 새로운 종류 출력문을 추가할 때마다 switch 문을 변경할 것인가.
1 | void print() { |
플러거블 셀렉터는, 리플랙션을 이용해서 동적으로 메서드를 호출한다.
1 | void print() { |
메서드를 달랑 한개만 가지는 하위 클래스들이 여러 개 있을 때, 확실히 직관적인 상황에서 코드 정리 목적으로 사용해라.
팩토리 메서드
다음 메서드가, 팩토리 메서드이다. 객체를 생성하기 때문이다.
1 | static Dollar dollar(int amount) { |
클라이언트는 다음과 같이 사용한다.
1 | Dollar five = Money.dollar(5); |
팩토리 메서드의 단점은, indirection 이다. 메서드가 생성자처럼 생기지 않았지만, 이 안에서 객체를 생성한다는 사실을 기억해야한다. 유연함이 필요 없다면, 생성자를 써라.
사칭 사기꾼
기존의 코드에 새로운 변이를 도입하려면?
기존의 객체와 같은 프로토콜(인터페이스) 를 갖지만 구현은 다른 새로운 객체를 추가해라.
예를 들면,
- 널 객체 : 데이터가 없는 상태를, 데이터가 있는 상태와 동일하게 취급 가능
- 컴포지트 : 객체의 집합을 단일 객체 처럼 취급 가능.
컴포지트
하나의 객체가 다른 객체 목록의 행위를 조합한 것처럼 행동하게 하려면?
객체 집합을 나타내는 객체를 단일 객체에 대한 임포스터로 구현해라. ( Folder 는 Folder 를 포함한다. )
수집 매개변수
여러 객체에 걸쳐 있는 오퍼레이션의 결과를 수집하라면?
결과가 수집될 객체를 각 오퍼레이션의 매개 변수로 추가해라.
1 | String toString() { |
테스트 주도 개발 <켄트 벡>