GRASP 패턴
이번 포스트에서는 GRASP Pattern 에 대해 다룬다. (GRASP : Designing Objects with Responsibilites)
GRASP
GRASP 란?
GRASP = General Responsibility Assignment Software Patterns
- 객체지향 설계에서 책임을 할당하는 데 도움을 주는 9가지의 설계 원칙
- 설계 모델에서 클래스 간의 책임 분배를 명확히 하기 위한 가이드
Responsibility
- A contract or obligation of a class
- Responsibility 는 메서드가 아니다. (메서드가 수행해야 할 역할)
Knowing Responsibility
- 정보를 알고 있어야 한다.
- 예시) Sale은 자신의 총액을 알고 있어야 한다.
Doing Responsibility
- 무언가를 수행해야 한다.
- Sale은 SalesLineItems 를 생성해야 한다.
Modularity
- 시스템을 작은 단위로 나누고, 책임을 분산시켜 복잡도를 낮춤
- Separation of Concerns : 관심사의 분리
- Information Hiding : 정보 은닉
Coupling vs Cohesion
Coupling (결합도)
- 클래스 / 모듈 간의 의존성 정도
- 높은 결합도의 문제점
- 하나를 변경하게 되면 연쇄적으로 변경해야한다.
- 재사용하기가 어렵다.
- 테스트의 복잡도
- ‘attribute referencing’, ‘mehod referencing’, ‘subclass’, ‘implements’ 를 통해 사용
Pursue Low Coupling
Cohesion (응집도)
- 한 클래스의 내부 책임들이 얼마나 밀접하게 관련되어 있는가
- 높은 응집도의 장점
- 이해하기 쉽고, 유지보수에도 쉽다.
- 코드 재사용을 하기 쉽다.
- 결합도를 낮춰준다.
Pursue High Cohesion
GRASP 의 9가지 패턴
1. Creator Pattern
- Creator Pattern (생성자 패턴)
- 누가 어떤 객체 A를 생성해야 하는지에 대한 책임 배분 원칙
- 해당 조건 기준 (B 클래스에 A 객체 생성)
- B가 A를 포함하거나 집합으로 가짐
- B가 A를 기록함
- B가 A를 빈번하게 사용하는 주체임
- B가 A를 생성하는데 필요한 초기화 데이터를 가지고 있음.
- 장점 : 객체 사이의 coupling을 줄이고, cohesion을 높이며, 객체 생성을 자연스럽고 직관적으로 위임할 수 있다.
2. Information Expert Pattern
- Information Expert Pattern (정보 전문가 패턴)
- 어떤 객체에게 특정 책임을 부여할 것인가
- 해당 책임을 수행하기 위해 필요한 정보를 가장 잘 알고 있는 객체에게 그 책임을 부여함.
- 정보가 있는 객체가 책임도 가진다.
- 장점 : encapsulation을 유지하고, 책임을 적절히 분산시켜 Low Coupling + High Cohesion을 달성
- 단점 : 과도하게 적용시에 Separation of Concerns를 위반할 수 있음.
- 데이터 베이스의 저장 책임을 넘기면 Cohesion이 낮아진다.
3. Controller Pattern
- Controller Pattern (조정자 패턴)
- 시스템 이벤트를 UI가 아닌 누가 받아야 하는가?
- 시스템 이벤트를 처리하는 책임을 UI가 아닌 다음 중 하나에 부여
- Facade Controller : 시스템 전체를 대표하는 객체
- Use Case or Session Controller : 특정 시나리오를 처리하는 객체
- UI는 사용자 이벤트만 받고, 이벤트를 Controller에 전달
- 장점 : UI와 도메인 로직 분리, 재사용성의 증가, 복잡한 흐름을 한 곳에서 제어 가능함.
- 주의 : Controller 가 너무 많은 역할을 맡으면, Bloated Controller가 된다.
4. Low Coupling Pattern
- Low Coupling Pattern (낮은 결합도)
- 클래스 간 의존성이 높으면, 변경에 취약해지고 재사용성이 어려움
- 책임을 부여할 때, 다른 클래스에 대한 불필요한 의존을 최소화하라
- 클래스 간 결합을 느슨하게 유지하면 변경 영향이 줄어든다.
- 패턴들을 적용하면서도 결합도를 고려하여 책임 배분
- 장점 : 유지보수에 쉽고, 테스트와 재사용에 용이하며 변경에 강하다.
5. High Cohesion Pattern
- High Cohesion Pattern (높은 응집도)
- 하나의 클래스가 너무 많은 역할을 맡으면 이해하거나 유지보수하기가 어렵다.
- 관련된 책임들만 하나의 클래스에 집중시켜라
- 객체가 명확한 목적을 가지도록 책임을 분산
- 하나의 클래스가 집중된 역할을 하게 되면 이해, 테스트, 변경하기에 쉬움.
- 장점 : 구조적 명확성, 유지보수성 증가, 자연스럽게 Low Coupling 유도
6. Pure Fabrication Pattern
- Pure Fabrication Pattern (순수 창조물)
- 높은 응집도와 낮은 결합도를 유지하려고 하는데, 도메인 개념에 해당하는 적절한 클래스가 존재하지 않는 경우
- 현실 세계와 무관하더라도, 높은 응집도와 낮은 결합도를 위해 인공적인 클래스를 만든다.
- 도메인 모델에 등장하지 않은 클래스
- 장점 : 응집도 증가, 도메인 모델 단순화, 코드 재사용성 증가
7. Polymorphism Pattern
- Polymorphism Pattern (다형성)
- 타입에 따라 행동이 달라져야 할 때, 누가 그 행동을 책임질까
- 행동이 바뀌는 타입 각자에게 그 책임을 할당하고, 공통 인터페이스로 메시지를 보낸다.
- 장점 : 선택 조건 없이 객체가 알아서 행동하기에 새로운 타입을 쉽게 추가할 수 있음.
- 단점 : 클래스 수가 증가함. 과도한 일반화는 오히려 가독성 저해 가능
8. Indirection Pattern
- Indireciton Pattern (간접화)
- 두 객체가 직접 결합되면 유연성이 낮고 변경에 취약
- 객체들 사이에 중간 객체를 두어 직접 결합 대신 중간 단계를 통해 통신하게 만든다.
- 장점 : 낮은 결합도, 유연성 증가 (외부 변경에 대한 방어)
9. Protected Variations Pattern
- Protected Variations Pattern (변화 보호)
- 시스템 내부에서 어떤 부분은 변화 가능성이나 불안전성이 높음
- 다른 요소들이 이런 변화에 직접 노출되면 위험
- 변화 가능성이 있는 요소 앞에 안정된 인터페이스 (보호막)을 둠으로써 나머지 요소들이 영향을 받지 않도록 함.
- OCP (Open-Closed Principle) 와 유사 : 확장에는 열려 있고, 변경에는 닫혀 있어야 함.
- 장점 : 변화에 대한 방어적 설계가 가능, 플러그인 방식 구조 유도
GRASP 9가지 패턴 요약
| 패턴 | 목적 | 핵심 아이디어 |
|---|---|---|
| Information Expert | 책임 할당 | 필요한 정보를 알고 있는 객체에게 책임 부여 |
| Creator | 객체 생성 책임 | 포함, 기록, 초기화 정보가 있는 클래스가 생성 책임 가짐 |
| Controller | 시스템 이벤트 처리 | UI 외부의 시스템 연산을 수신/조정하는 객체 |
| Low Coupling | 결합도 최소화 | 불필요한 의존 최소화 (유지보수성 향상) |
| High Cohesion | 응집도 극대화 | 관련 책임을 한 클래스에 집중 |
| Polymorphism | 행동의 다양성 대응 | 행동이 타입에 따라 달라질 경우 다형성을 활용 |
| Pure Fabrication | 책임 분리 | 도메인 개념이 아닌 인공 클래스에 책임 위임 |
| Indirection | 간접화 | 중간 객체로 결합도 줄이기 |
| Protected Variations | 변화 보호 | 변동성 포인트를 인터페이스로 보호 (OCP 원칙과 유사) |