정리
데이터보다 행동을 먼저 결정하라
클라이언트의 관점에서 객체가 수행하는 행동이란 곧 객체의 책임을 의미한다.
협력이라는 문맥 안에서 책임을 결정하라
협력을 시작하는 주체는 메시지 전송자이기 때문에 협력에 적합한 책임이란 메시지 수신자가 아니라 메시지 전송자에게 적합한 책임을 의미한다.
객체가 메시지를 선택하는 것이 아니라 메시지가 객체를 선택하게 해야 한다.[Metz12]
객체를 가지고 있기 때문에 메시지를 보내는 것이 아니라 메시지를 전송하기 때문에 객체를 갖게 된 것이다.[Metz12]
메시지는 클라이언트의 의도를 표현하며,
객체를 결정하기 전에 객체가 수신할 메시지를 먼저 결정한다.
메시지를 수신하기로 결정된 객체는 메시지를 처리할 ‘책임’을 할당받게 된다.
책임 주도 설계
- 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다.
- 시스템 책임을 더 작은 책임으로 분할한다.
- 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다.
- 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.
- 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다.
GRASP 패턴[Larman04]
General Responsibility Assignment Software Pattern(일반적인 책임 할당을 위한 소프트웨어 패턴)
올바른 도메인 모델이란 존재하지 않는다.
도메인 모델은 도메인을 개념적으로 표현한 것이지만 그 안에 포함된 개념과 관계는 구현의 기반이 돼야 한다. 이것은 도메인 모델이 구현을 염두에 두고 구조화되는 것이 바람직함을 의미한다.
정보 전문가에게 책임을 할당하라.
- 메시지를 전송할 객체는 무엇을 원하는가?
메시지는 메시지를 수신할 객체가 아니라 메시지를 전송할 객체의 의도를 반영해서 결정해야 한다.
- 메시지를 수신할 적합한 객체는 누구인가?
INFORMATION EXPERT(정보 전문가)패턴
책임을 수행하는 데 필요한 정보를 가장 잘 알고 있는 전문가에게 그 책임을 할당하는 것이다.
객체는 자율적인 존재여야 하기 때문.
LOW COUPLING(결합도)패턴 & HIGH COHESION(응집도)패턴
LOW COUPING 패턴
설계의 전체적인 결합도가 낮게 유지되도록 책임을 할당하라.
HIGH COHESION 패턴
높은 응집도를 유지할 수 있게 책임을 할당하라.
CREATOR(생성자) 패턴
어떤 방식이로든 생성되는 객체와 연결되거나 관련될 필요가 있는 객체에 해당 객체를 생성할 책임을 맡기는 것이다. → 두 객체는 서로 결합된다.
이미 결합돼 있는 객체에게 생성 책임을 할당하는 것은 설계 상의 전체적인 결합도에 영향을 미치지 않는다.
객체 A를 생성해야 할 때 아래 조건을 최대한 많이 만족하는 B에게 객체 생성 책임을 할당하라.
- B가 A객체를 포함하거나 참조한다.
- B가 A객체를 기록한다.
- B가 A객체를 긴밀하게 사용한다.
- B가 A객체를 초기화하는 데 필요한 데이터를 가지고 있다(이 경우 B는 A에 대한 정보 전문가다)
클래스 응집도 파악하기
변경의 이유에 따라 클래스를 분리해야 한다.
설계를 개선하는 작업은 변경의 이유가 하나 이상인 클래스를 찾는 것으로부터 시작하는 것이 좋다.
코드를 통해 변경의 이유를 파악할 수 있는 방법
- 인스턴스 변수가 초기화되는 시점을 살펴보는 것.응집도가 낮은 클래스는 객체의 속성 중 일부만 초기화하고 일부는 초기화되지 않은 상태로 남겨진다.
- 이를 함께 초기화되는 속성을 기준으로 코드를 분리해야 한다.
- 응집도가 높은 클래스는 인스터스를 생성할 때 모든 속성을 함께 초기화하는 반면,
- 메서드들이 인스턴스 변수를 사용하는 방식을 살펴보는 것.반면, 메서드들이 사용하는 속성에 따라 그룹이 나뉜다면 클래스의 응집도가 낮다고 볼 수 있다.
- 속성 그룹과 해당 그룹에 접근하는 메서드 그룹을 기준으로 코드를 분리해야 한다.
- 모든 메서드가 객체의 모든 속성을 사용한다면 클래스의 응집도는 높다고 볼 수 있다.
다형성을 통해 동일한 책임을 수행하는, 동일한 역할을 수행하는 인스턴스를 분리한다.
구현을 공유해야 할 필요가 있다면 추상클래스를,
구현을 공유할 필요 없이 객체들의 책임만 정의하고 싶다면 인터페이스를 사용한다.
POLYMORPHISM(다형성) 패턴
타입을 명시적으로 정의하고 각 타입에 다형적으로 행동하는 책임을 할당하라.
if else 와 같은 조건 논리를 사용해서 설계한다면 새로운 변화가 일어난 경우 조건 논리를 수정할 필요가 있다. 이는 프로그램을 수정하기 어렵고 변경에 취약하게 만든다.
조건 논리를 사용하는 대신 다형성을 이용해 새로운 변화에 대해 쉽게 확장하기를 권고한다.
PROTECTED VARIATIONS(변경 보호) 패턴
변화가 예상되는 불안정한 지점들을 식별하여 그 주위에 안정된 인터페이스를 형성하도록 책임을 할당하라.
이는 책임 할당의 관점에서 캡슐화를 설명한 것이다.
“설계에서 변하는 것이 무엇인지 고려하고 변하는 개념을 캡슐화하라[GOF94]
변경이 될 가능성이 높다? → 캡슐화하라.
몬스터 메서드
응집도가 낮기 때문에 이해하기도 어렵고 재사용하기도 어려우며 변경하기도 어려운 긴 메서드[Feathers04]
객체로 책임을 분배할 때 가장 먼저 해야하는 일은 메서드를 응집도 있는 수준으로 분해하는 것.
긴 메서드를 작고 응집도 높은 메서드로 분리하면 각 메서드를 적절한 클래스로 이동하기 더 수월해지기 때문이다.
메서드를 다른 클래스로 이동시킬 때는 인자에 정의된 클래스 중 하나로 이동하는 경우가 일반적임.
읽고 난 후
저번 장에서 데이터 중심 설계에 문제점들을 살펴본 것에 이어 이번 장에선 어떻게 책임 주도 설계를 해야할 지 알아봤다. 책임 주도 설계를 많이 안해 본 개발자를 위해 대안이 인상깊었다.
여기서 대안이라함은 먼저 책임과 협력에 관해 고민하기 전에 일단 실행되는 코드를 얻고 이후에 책임과 협력에 대해 생각해보는 것이다. 즉 리팩토링을 하는 것인데 이번 오브젝트 책을 읽고, 저번 스프링 프로젝트를 진행하면서 기능은 잘 작동하지만 설계측면에서 아쉬운 부분이 있어 리팩토링을 할 예정이었다. 이번에 알게된 GRASP패턴을 적용하여 훌륭한 설계를 얻어봐야겠다..!
'독서 > 오브젝트(조영호 저)' 카테고리의 다른 글
7장 객체 분해 (0) | 2023.06.02 |
---|---|
6장 메시지와 인터페이스 (0) | 2023.06.02 |
4장 설계 품질과 트레이드오프 (0) | 2023.06.02 |
3장 역할, 책임, 협력 (0) | 2023.06.02 |
2장 객체지향 프로그래밍 (0) | 2023.05.30 |