3 분 소요

이번 포스트에서는 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 원칙과 유사)