Strategy 패턴에 대한 사항은 다음 책을 참조하시거나
책 살 돈이 없다 싶으신 분들은 아래 글을 보실 수 있습니다.
- 2006/10/08 Strategy Pattern 예제(끝)
- 2006/10/08 Strategy Pattern 예제(계속)
- 2006/10/08 Strategy Pattern 예제(계속)
- 2006/10/08 Strategy Pattern 예제
내용 보장 못함.. :)
제가 작성하려는 글은 아래 책의 188쪽부터 소개된 내용을 기반으로
이클립스에서 리팩토링을 수행하는 과정에서 주목할만한 부분을 남겨두기 위한 일종의 SNAPSHOT입니다. (이하 존칭 생략)
먼저 다른 녀석에게 옮길 메소드/행위 혹은 책임을 선정한다. (
② 사례연구, 단일 책임 원칙 참조) 위임할 대상은 Student의 협업 객체 혹은 Collaborator가 된다. 아니면 peer(
객체 지향 기본에 대한 메모 참조)라고 하든.. 암꺼나.. you want
협업 대상과의 관계를 정의해야 한다. 코딩으로 말하자면 멤버 변수를 정의하는 것이 된다. 빨간 줄을 제거하다 보면 GradingStrategy라는 하나의 인터페이스와 이것을 상속한 RegularGradingStrategy 클래스를 생성하게 된다.
public class Student {
private GradingStrategy gradingStrategy = new RegularGradingStrategy();
여기서 몇 가지 선택 사양이 등장한다.
1. 협업 대상 객체의 타입/클래스 이름 결정
2. 타입을 인터페이스로 할 것인가? 추상 클래스로 할 것인가? 구체 클래스로 할 것인가?
3. 초기화는 할 것인가? 한다면 어떤 방식으로?
대개 경험에 의해서 순식간에 결정하지만 설명하자면 엄청 길다.
1은
좋은 작명은 internal DSL의 시작 참조. 2는 Strategy 패턴을 적용하려는 경우에는 구체 클래스 보다는 추상 클래스나 인터페이스를 쓰는 것이 좋다. 이유는
개방-폐쇄 원칙참조. 3은 디폴트의 문제다. 선호의 문제인데, 개인적으로는 루비의 경우와 같이 직관적인 디폴트가 사전에 정의되는 것을 좋아한다.
협업 객체와 관계를 맺었으니 임무/책임을 할당/위임하자.
드래그앤드롭으로 리팩토링이 가능하다. 구현 내용이 남아 있다. 로직을 남기고 싶다면(복잡한 알고리즘인 경우) 드래그앤드롭 대신에 복사를 하는 것이 더 좋다. 단축키
Ctrl+1을 눌러 빠른 보정(Quick Fix) 힌트에서 Remove method body를 선택하여 구현을 날린다. 인터페이스인 만큼
계약(contract)만 남기는 것이다.
또, 문제가 발생한다. 인터페이스에는 private이 존재할 수 없기 때문이다. Quick Fix보다는 타이핑으로 private을 public으로 변경하는 것이 좋다. 3.1 버전의 이클립스에서는 public 변환은 힌트로 제공하지 않는다.
주의 깊게 다시 보면,
책임의 위임 과정에서 '객체 사이의 인터페이스(method)'가 public으로 변경되는 점과 메소드 몸체가 날아가면서 해당 책임이 추상화 된 형태로 협력 객체에 할당되는 것을 엿볼 수 있다.
추상화 된 것은 실행이 불가능 하기 때문에 실체화(realization)를 해보자. 추상화에 익숙하지 않은 개발자는 머리 아플 수 있는 기괴한 표현이지만, 실상은 별 것 아니다. :)
일단, RegularGradingStrategy 클래스의 빨간 줄을 지우기 위해 빠른 보정 힌트에서 Add unimplemented methods를 선택한다. 그리고, 구현은 직접 타이핑 하지 말고 앞서 Students에 있던 basicGradePointsFor 메소드 구현을 가져오자. 기본 학점 부여 정책이니까...
마지막으로 Student에서 내부 인터페이스/private 메소드를 호출하던 것을 위임으로 해결 하도록 다시 말해서 협업 객체의 메소드 호출로 변경한다.
for (Grade grade : grades) {
total += gradePointsFor(grade);
}
코드가 위와 같은 식이었다면..
for (Grade grade : grades) {
total += gradingStrategy.gradePointsFor(grade);
}
이렇게만 바꿔주면 된다.
마무리가 남는다. 이클립스의 경고 기능이 큰 도움이 된다. 평소 노란등이 보기 싫다고 꺼두는 사람을 봤는데... 좋은 습관이 아니다. :)
Strategy 패턴 적용 이전에 쓰이던 내부의 플래그 성격의 속성이 쓰이지 않게 되었음을 의미한다.
플래그 성격의 속성은 Strategy의 종류/유형 즉, Strategy를 구현한 구체 클래스의 타입으로 변경되어서 사라지게 되는 것이다.