13장. 실전 디자인 패턴
디자인 패턴의 정의
패턴(Pattern)은 특정 컨텍스트 내에서 주어진 문제의 해결책이다.
- 컨텍스트(context): 패턴이 적용되는, 반복적으로 일어날 수 있는 상황
- 문제(problem): 컨텍스트 내의 제약조건과 이뤄야 하는 목표
- 해결책(solution): 제약조건 속에서 누가 적용해도 목표를 이룰 수 있는 일반적인 디자인
어떤 컨텍스트 내에서 일련의 제약조건에 의해 영향을 받는 문제가 발생했다면, 그 제약조건 내에서 목적 달성을 위한 해결책이 되는 디자인을 적용하면 된다.
패턴을 정의할 수 있어야 패턴 카탈로그를 만들 수 있다.
→ 패턴은 반복적으로 등장하는 문제에 적용할 수 있어야 하며, 이름을 가지고 있어야 한다.
패턴 카탈로그
GoF(Gang of Four)의 디자인 패턴에서 처음 등장했으며, 일련의 패턴을 정해서 각각의 패턴을 다른 패턴과 비교해서 자세하게 설명한다.
패턴의 용도와 패턴이 만들어진 배경, 적용할 수 있는 범위, 해결책의 디자인 및 그 해결책을 적용한 결과(장단점)와 같이 다양한 내용이 적혀 있음
Intent 패턴의 역할이 간단하게 기술됨
Motivation | 문제를 기술하고, 주어진 해결책이 어떤 식으로 그 문제를 해결하는지 보여주는 구체적인 시나리오 |
Applicability | 패턴을 적용할 수 있는 상황 |
Structure | 패턴 내 클래스들의 관계를 보여주는 다이어그램 |
Participants | 패턴 내의 클래스와 객체들, 그리고 각각의 임무와 역할 설명 |
Collaborations | 각 Participants가 패턴 내에서 어떻게 서로 도움을 주는지 설명 |
Consequences | 패턴을 사용했을 때의 효과(장단점) |
Implementation/Sample Codes | 패턴을 구현할 때 필요한 기술과 주의사항 및 예제 코드 |
Known Uses | 실제 시스템에서 이 패턴을 사용하는 예시 |
Related Patterns | 이 패턴과 다른 패턴 사이의 관계 |
패턴 카탈로그 활용 순서
- 모든 패턴, 패턴들의 관계를 먼저 파악하고 있어야 함
- 적용할 패턴을 선정
- 적용 대상 패턴의 섹션을 확인(구조, 구성요소, 샘플 코드 등)
- 적용 대상 패턴의 결과를 확인 → 새로운 패턴 적용에 따른 의도치않은 부작용 방지
새로운 디자인 패턴을 발견하기
1. 숙제를 먼저 하자.
새로워 보이는 패턴도 사실은 기존 패턴의 변형에 불과한 경우가 많다.기존의 패턴을 확실하게 공부하면 패턴을 알아보는 눈과 패턴을 연관 짓는 능력이 발달한다.
2. 오랜 시간에 걸쳐서 심사숙고한다.
반복적으로 발생하는 문제를 해결할 수 있는 디자인인지, 적용 범위가 너무 좁지는 않은지 고민해야 한다.
3. 남들도 이해할 수 있도록 종이 위에 적어본다.
다른 사람들이 피드백을 제공할 수 있도록 문서화하자.위의 GoF 템플릿을 활용해서 공유할 수 있다.
4. 새로운 패턴을 다른 사람들이 사용하게 하면서 계속 다듬기
다른 개발자들이 새 패턴을 시험해 보도록 하고 피드백을 얻어 반영하고, 다시 검증을 받는 과정을 여러 번 반복
5. 3의 규칙을 적용한다.
실전 문제 해결에 3번 이상 적용되어야 패턴이 될 수 있다.
디자인 패턴 분류하기
제일 유명한 분류 방법: 패턴 카탈로그에서 제시한 생성, 행동, 구조 이라는 3가지 범주로 용도에 따라 나누기
이렇게 패턴들을 범주로 나눠 놓으면, 각각을 조금 더 추상적인 수준에서 생각하는데 도움이 된다.
- 구체적으로 어떤 패턴을 사용할 지 바로 결정할 수 없더라도, 어느 범주의 패턴을 사용해야 될지는 확신할 수 있다.
또한 같은 범주 내의 패턴들끼리의 관계를 생각하기도 좋다
이외에도 클래스 패턴과 객체 패턴이라는 분류 방법도 존재
- 클래스 패턴
- 클래스 사이의 관계가 상속으로 어떻게 정의되는지를 다루는 패턴
- 대부분 컴파일할 때 결정된다.
- 객체 패턴
- 객체 사이의 관계를 다루며, 보통 구성으로 정의된다.
- 대부분 실행 중에 관계가 결정되므로 보다 동적이고 유연하다.
패턴으로 생각하기
아무리 패턴과 관련된 이론을 많이 알고 있어도 경험이나 연습 없이는 별로 도움이 되지 않는다.
패턴 적용 여부를 결정할 때 도움이 될 만한 내용들을 정리하면 다음과 같다.
최대한 단순하게 (KISS, Keep It Simple)
- 이 문제에 어떻게 패턴을 적용할 수 있을까 (X) → 어떻게 하면 단순하게 해결할 수 있을까 (O)가장 단순하고 유연한 디자인을 만들 때 패턴이 있어야 한다면 그때 패턴을 적용하자
디자인 패턴은 만병통치약이 아니다
- 패턴은 반복적으로 발생하는 문제의 일반적인 해결책패턴 사용 시에는 그 패턴이 자신이 설계한 디자인에 미칠 영향과 결과를 주의깊게 생각해봐야 함
패턴이 필요할 때
- 디자인상의 문제에 적합하다는 확신이 들 때 패턴을 도입더 간단한 해결책이 있다면 패턴 적용 전 그 해결책의 사용을 고려해 봐야 한다.언제 패턴을 적용할지 올바르게 결정하려면 상당한 경험과 지식이 축적되어야 함어떤 패턴을 써야할지 잘 모르겠다면 패턴 카탈로그에서 패턴의 용도와 적용 대상 부분을 살펴보자 → 찾았다면 그 패턴의 결과 부분을 보고 적용 시 나머지 부분에 미치는 영향을 파악발생 가능성이 높은 실질적인 변경에 대비해서 패턴을 적용하는 것이 바람직함
리팩터링과 패턴
- 리팩터링의 목적은 구조 개선이며, 이 단계에서도 패턴 도입을 고민할 수 있다.조건문이 많은 코드에 상태 패턴을 고려할 수 있다.팩토리 패턴을 이용해 구상 클래스의 의존성을 깔끔하게 정리할 수 있다.
꼭 필요하지 않은 패턴은 빼자
- 시스템이 복잡해지며 처음에 기대한 유연성이 발휘되지 못한다면 과감히 제거패턴보다 간단한 해결책이 더 나을 것 같다 싶을 때도 제거
꼭 필요하지 않은 패턴을 미리 적용할 필요는 없다.
- 변화에 대처하는 디자인을 만들 때 패턴을 적용해 변화에 대비꼭 필요하지 않을 때 괜히 패턴을 추가하면 시스템만 복잡해지고, 나중에는 사용되지 않을 수도 있음
정리
- 디자인 패턴은 도구에 불과하며, 필요할 때만 써야하는 도구임
- 애플리케이션에서 나중에 확실하게 생길 수 있는 변경 사항을 처리하는데 필요하면 디자인 패턴 적용 (확장성이 필요한 경우 !!!!)
- 무지성으로 도입하여 쓰다보면 더 복잡해지기 때문에 지양해야 함
- 디자인 패턴이 아닌 디자인 원칙을 써서 훨씬 간단하게 문제를 해결할 수도 있음 (결국 디자인 패턴도 객체지향 원칙을 활용한 패턴이기 때문)
안티 패턴
어떤 문제의 나쁜 해결책에 이르는 길을 알려줌
일상적인 문제의 자주 반복되는 나쁜 해결책을 문서화하여 다른 개발자들이 똑같은 실수를 반복하지 않도록 방지해주는 역할
구성
문제 | 디자인 페턴에서의 문제 |
컨텍스트 | 디자인 패턴에서의 컨텍스트 |
원인 | 나쁜 해결책에 빠지기 쉬운 이유 |
잘못된 해결책 | 나쁜(하지만 여전히 매력적인) 해결책 |
바람직한 해결책 | 좋은 해결책에 이르는 방법 |
예시 | 안티 패턴을 볼 수 있는 예 |