Don't Talk to Strangers 라고도 불리는 디미터법칙에 대해 알아보자!
(아래의 블로그를 많이 참고하여 작성합니다. 좋은 글이니까 읽어보는 걸 추천드립니다)
객체는 그것이 내부적으로 보유하고 있거나 메시지를 통해 확보한 정보만 가지고 의사 결정을 내려야 한다
어원
- 디미터라는 프로젝트는 소프트웨어를 단순히 개발하는 것이 아니라 소프트웨어를 성장시키는 방법을 사용
- 객체지향 프로그래밍에서 느슨하게 결합된 코드를 작성하는 실용적인 접근 방식
- 객체 구조의 변화와 불안정이 자주 발생, 객체 연결에 관한 정보를 지닌 코드는 불안정
- 객체들의 협력 경로를 제한하면 결합도를 효과적으로 낮출 수 있음
어원을 살펴보면 디미터법칙은 객체들간의 느슨한 결합을 추구하는 원칙인 것 같다
의미
- 디미터 법칙은 9개의 GRASP 패턴 중 하나로, Don't Talk to Stranger패턴으로 불리는 중요한 객체 설계 원칙
- 긴 객체 구조의 경로를 따라 멀리 떨어져 있는 간접적인 객체에게 메시지를 보내는 설계를 피하라는 것
- 이러한 설계는 일반적으로 불안정한 지점, 객체 구조의 변화에 부서지기 쉬움
- 객체의 내부 구조에 강하게 결합되지 않도록 협력 경로를 제한하자
- 어떤 객체에게 메시지를 보내야 하는가에 대한 제약을 가함. 메소드 안에서 다음 객체들에게만 메세지를 보내야함
- this 객체
- 메소드 매개변수
- this의 속성 + this의 속성인 컬렉션의 요소
- 메소드 내에서 생성된 객체
- 객체는 자기 자신을 책임지는 자율적인 존재 -> 책임을 가진 응집도 높은 객체
- 객체의 내부 구조를 묻는 메시지 x 수신자에게 무언가를 시키는 메시지가 좋은 메시지이다
- 객체는 내부적 보유 or 메시지를 통해 확보한 정보만 가지고 의사 결정을 해야함. 다른 객체를 탐색하여 뭔가 일어나게 하면 안 됨
- 모듈은 자신이 조작하는 객체의 속사정을 몰라야함. 객체는 내부 구조를 공개하면 안된다
- 각 메소드가 메시지를 보낼 때도 극히 제한된 클래스 집합에 속하는 객체에게만 보내야 한다
- 한 모듈은 주변 모듈을 모를수록 좋다. A가 B를 사용, B가 C를 사용 -> A가 C를 알 필요는 없음
- 자기가 소유한 장난감, 자기가 만든 장난감, 누군가 나에게 준 장난감하고만 놀기. 장난감의 장난감과 놀면 안됨
- 낯선 사람은 경계하고 친구랑만 놀아라
디미터 법칙을 지켰을 때 효과
- 느슨히 결합된 클래스 생성
- 클래스들의 구현 비밀은 캡슐화로 감춰짐(상세한 내용을 알 필요 없다)
- 좀 더 에러가 적은 클래스들을 만들 수 있다(함수를 호출하는 응답집합 크기를 줄일 수 ㅇ)
- 결합도를 낮춰 변화의 파급력이 적어짐
법칙의 적용
디미터 법칙은 경우에 따라 판별이 애매함 -> 이분법적으로 생각하지 않기
ex) 객체가 자료구조라면 내부 구조를 노출할 수밖에 없다 -> 디미터 법칙 적용 x
디미터 법칙을 따르는 형태의 코드는 단순함
object.method(parameter);
디미터 법칙을 위반한 전형적인 코드 형태
object.getChild().getContent().getItem().getTitle();
(아.. 뼈를 맞아버렸다)
- 디미터 법칙을 위반하면 위와 같이 접근자(getter) 메서드가 기차처럼 연이어 이어지는 형태가 나타난다. 이를 메시지 체인이라고 한다
- 원거리의 간접적인 객체에 메시지를 보내기 위하여 객체의 연결 경로를 따라 더 멀리 순회하는 형태이다
- 이는 객체들이 어떻게 연결되어있는지를 나타내는 특정한 구조와 결합됨
- 객체의 구조는 변화할 수 있기 때문에 순회 경로가 길어질수록 프로그램은 더 불안정해진다
디미터 법칙을 따르지 않으면 메시지 체인(Message Chains) 이라는 악취가 나게 된다
디미터 법칙은 결합도와 관련된 것
디미터 법칙은 오직 하나의 도트만을 사용하라는 말로 요약되지만, 여러 개의 도트를 쓴다고 해서 디미터 법칙이 위반되는 것은 아니다.
디미터 법칙은 결합도와 관련된 것이고, 결합도가 문제가 되는 것은 객체의 내부 구조가 외부로 노출되는 경우로 한정됨
ex) java stream에서 여러개로 연결된 체인형태는 디미터법칙을 위반한 것이 아니다 (Intstream이라는 동일한 클래스의 인스턴스를 반환하기 때문)
메시지 체인의 리팩토링
1. 대리 객체 은폐 기법
메시지체인으로 인해 클라이언트가 해당 체인에 구속된다. 이렇게 되면 그 사이의 관계들을 수정할 경우 클라이언트도 수정해야한다. 이럴 때는 대리 객체 은폐(Hide DElegate)를 실시해야한다.
이 기법은 원칙적으로 체인을 구성하는 모든 객체에 적용할 수 있지만, 그렇게 하면 모든 중간 객체가 중개 메서드로 변해서 과잉 중개 메서드(middle man)의 구린내를 풍기는 문제가 흔히 발생한다.
그래서 차라리 결과 객체가 어느 대상에 사용되는지를 알아내는 방법이 맞다.
- 객체가 어느 대상에 사용되는지 알아낸 후,
- 객체가 사용되는 코드 부분을 메서드 추출을 통해 별도의 메서드로 빼낸다
- 해당 메서드를 이동하여 체인 아래로 밀어낼 수 있는지 여부를 검사한다
만약 체인에 속한 객체 중 한 객체의 여러 클라이언트가 나머지 객체들에 왕래한다면 그 기능을 수행하는 메서드를 추가하면 된다.
2. 객체지향 생활 체조
객체지향 생활 체조에 디미터 법칙과 관련된 규칙이 있다.
4. 한 줄에 점을 하나만 찍는다
- 종종 하나의 동작에 대해 어떤 오브젝트가 맡고 있는지 구분하기 어려울 때가 있음
- 여러 개의 점이 들어 있는 코드 -> 책임소재의 오류를 많이 발견할 수 있음
- 어떠한 코드 한 줄에서라도 점이 하나 이상 있으면 그른 곳에서 동작이 일어나고 있다는 뜻(다른 두 오브젝트들을 동시에 다루고 있을 수 있다)
- 이 경우 그 오브젝트는 너무 많은 사람들에 대해 지나치게 알고 있는 꼴
- 대상 오브젝트는 딴 오브젝트에 깊숙이 관여하고 있을 수 있음(캡슐화를 어기고 있다는 방증)
- 문제의 동작을 관련 오브젝트 중에 하나로 옮겨보자.
- 오브젝트가 자기 속을 들여다 보려 하기보다는 뭔가 작업을 하도록 만들려고 해야함
- 캡슐화의 주요점은 클래스 경계를 벗어나 알 필요가 없는 타입으로 진입하지 않는 것
'소프트웨어 설계' 카테고리의 다른 글
복잡한 쿼리를 보내더라도 디비에서 처리 vs 서버에서 처리 (0) | 2024.03.14 |
---|---|
단위테스트란? (0) | 2023.10.24 |
[책 리뷰] 객체지향의 사실과 오해 책을 읽고 정리함 (2) | 2023.10.23 |