본문 바로가기
책/오브젝트

05. 책임 할당하기

by 오오오오니 2025. 3. 17.

05. 책임 할당하기

비어 있음
2024년 4월 5일
책임 할당 과정은 일종의 트레이드오프 활동이다. 올바른 책임을 할당하기 위해서는 다양한 관점에서 설계를 평가할 수 있어야 한다.

책임 주도 설계를 향해

두 가지 원칙
데이터보다 행동을 먼저 결정하라
협력이라는 문맥 안에서 책임을 결정하라
너무 이름 시기에 데이터에 초점을 맞추면 객체의 캡슐화가 약화되기 때문에 낮은 응딥도와 높은 결합도를 가진 객체들로 넘쳐나게 된다.

협력이라는 문맥 안에서 책임을 결정하라

책임은 객체의 입장이 아니라 객체가 참여하는 협력에 적합해야 한다. 협력에 적합한 책임아란 메시지 수신자가 아니라 메시지 전송자에게 적합한 책임을 의미한다.
메시지를 먼저 결정하기 때문에 메시지 전송자의 관점에서 메시지 수신자가 깔끔하게 캡슐화 된다.

책임 주도 설계

책임 주도 설계의 핵심은 책임을 결정한 후에 책임을 수행할 객체를 결정하는 것이다.

책임 할당을 위한 GRASP 패턴

General Responsibility Assignment Software Pattern 의 약자로 책임을 할당할 때 지침으로 삼을 수 있는 원칙들의 집합을 패턴 형식으로 정리한 것

도메인 개념에서 출발하기

설계를 시작하기 전에 도메인에 대한 개략적인 모습을 그려 보는 것이 유용하다.
올바른 도메인 모델이란 존재하지 않는다.
도메인 모델의 포함된 개념과 관계는 구현의 기반이 돼야 한다.
도메인 모델은 바뀌게 되는데 유연성이나 재사용성 등과 같이 실제 코드를 구현하면서 얻게 되는 통찰이 역으로 도메인에 대한 개념을 바꾸기 때문이다.
실용적이면서 유용한 모델이 답이다.

정보 전문가에게 책임을 할당하라

INFORMATION EXPERT 패턴 : 책임을 수행하는 정보를 알고 있는 객체에게 책임을 할당하는 것
책임을 수행하는 객체가 정보를 ‘알고’있다고 해서 그 정보를 ‘저장’하고 있을 필요는 없다.
객체는 해당 정보를 제공할 수 있는 다른 객체를 알고 있거나 필요한 정보를 계산해서 제공할 수도 있다.

높은 응집도와 낮은 결합도

책임을 할당할 수 있는 다양한 대안들이 존재한다면 응집도와 결합도의 측면에서 더 나은 대안을 선택하는 것이 좋다.

LOW COUPLING 패턴

어떻게 하면 의존성을 낮추고 변화의 영향을 줄이며 재사용성을 증가시킬 수 있을까?
→ 결합도가 낮을 수 있게 책임을 할당

HIGH COHESION 패턴

어떻게 복잡성을 관리할 수 있는 수준으로 유지할 것인가?
→응집도가 높을 수 있게 책임을 할당

창조자에게 객체 생성 책임을 할당하라

CREATOR 패턴

객체를 생성할 책임을 어떤 객체에게 할당하지에 대한 지침을 제공한다.
B가 A 갹체를 기록한다.

구현을 통한 검증

DiscountCondition의 가장 큰 문제점은 변경에 취약한 클래스를 포함하고 있다는 것
즉, 수정해야 하는 이유를 하나 이상 가지는 클래스
새로운 할인 조건 추가 - if-else구문 수정
순번 조건을 판단하는 로직 → isSatisfiedSequence 메서드 내부 구현 수정
→ 응집도가 낮다.
변경의 이유에 따라 클래스를 분리해야 한다.

변경의 이유가 하나 이상인 클래스에 나타나는 위험 징후를 드러내는 패턴

클래스의 인스턴스 변수가 초기화되는 시점이 다르다
메서드들이 인스턴스 변수를 사용하는 방식이 속성에 따라 그룹으로 나뉜다.

타입 분리하기 - 다형성을 통해 분리하기

Movie 클래스가 PerideCondition, SequenceCondition 클래스 양쪽 모두에게 결합된다.
응집도가 높아졌지만 변경과 캡슐화라는 관점에서 보면 전체적으로 설계의 품질이 나빠진것이다.
두 클래스가 동일한 역할을 가지고 있기 때문에 추상화 할 수 있다.
추상 클래스 : 역할을 대체할 클래스들 사이에서 구현을 공유해야 할 필요가 있을 때
인터페이스 : 구현을 공유할 필요 없이 역할을 대체하는 객체들의 책임만 정의하고 싶을 때
즉, 객체의 타입에 따라 변하는 행동이 있다면 타입을 분리하고 변화하는 행동을 각 타입의 책임으로 할당하라 → POLYMORPHISM 패턴

변경으로부터 보호하기

DiscountCondition타입을 추가하더라도 Movie가 영향을 받지 않는다.
이처럼 변경을 캡슐화하도록 책임을 할당하는 것을 PROTECTED VARIATIONS 패턴이라고 부른다.
불안정한 지점들을 식별하고 그 주위에 안정된 인터페이스를 형성하라
설계에서 변하는 것이 무엇인지 고려하고 변하는 개념을 캡슐화하라

Movie 클래스 개선하기

변경과 유연성

현재의 설계에서는 할인 정책을 구현하기 위해 상속을 이용하고 있기 때문에 실행 중에 영화의 할인 정책을 변경하려면 새로운 인스턴스를 생성한 후 복사해야 한다.
번거롭고 오류가 발생하기도 한다. 할인 정책의 변경을 쉽게 수용할 수 있게 코드를 유연하게 만드는 것이 더 좋은 방법이다.
해결 방법은 상속 대신 합성을 사용하는 것
도메인 모델도 코드의 변화에 맞게 함께 변화해야 한다.

책임 주도 설계의 대안

최대한 빠르게 목적한 기능을 수행하는 코드를 작성 →
코드 상에 명확하게 드러나는 책임들을 올바른 위치로 이동시키는 것 (리팩터링)

느낀점

메시지 전송자의 관점에서 설계하는 것이 신기했다. 이렇게 하면 캡슐화를 잘 되는구나를 깨달았다.
4장 까지 읽고 책임 중심으로 설계하는 것의 장점을 이해했는데 그럼 어떻게 시작해야하나라는 의문이 들었다. 5장을 읽어보니 책임을 할당할 때 쓸 수 있는 원칙들(GRASP)이 있어서 객체지향 설계를 이해하는데 많이 도움이 되엇다.
정보전문가에게 책임을 할당하라는 원칙이 꼭 그 객체가 정보를 알고 있는 것이 아니라 정보를 알고 있는 다른 객체를 알고 있는 것을 의미할 수도 있다는 것이 인상 깊었다.
개발하면서 추상 클래스, 인터페이스, 클래스 분리 등에 대해서 매 순간 명확한 이유를 찾지 못했던 적이 있었다. 이 예제를 통해 처음에는 하나의 클래스나 다른 클래스의 구현됐을 때 응집도, 결합도, 캡슐화의 측면에서 코드를 분리해야 하는 이유를 명확히 해본 것이 인상 깊었다.
또한 리팩터링을 코드를 만들고 한참 뒤에 했었는데
기능을 만들고 나서 pr을 올리기 전에도 해야겠다고 생각했다.
또한 테스트 코드를 짜고 해야 리팩터링이라고 부를 수 있기 때문에 기능을 완성하면 테스트코드도 짜야겠다고 생각했다.
이 장에서 객체지향적으로 설계하는 과정을 점진적으로 볼 수 있어서 좀 추상적으로 와닿았던 객체지향에 대해 한걸음 더 다가갈 수 있었던 것 같다.

' > 오브젝트' 카테고리의 다른 글

07. 객체 분해  (0) 2025.03.17
06. 메시지와 인터페이스  (0) 2025.03.17
04. 설계 품질과 트레이드 오프  (0) 2025.03.17
03. 역할, 책임, 협력  (0) 2025.03.17
02. 객체지향 프로그래밍  (0) 2025.03.17