디미터 법칙(Law of Demeter)

2023. 11. 10. 08:22OOP

디미터 법칙이란?

디미터 법칙(Law of Demeter)은 데메테르 법칙이라고도 불리며 줄여서 LoD라고도 불립니다.

이 법칙은 "최소한의 지식 원칙(The Principle of Least Knowledge)"으로 알려져 있으며, 모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 것을 의미합니다.

 

Object-Oriented Programming: An Objective Sense of Style 에서 처음 소개되었습니다. 이 글의 저자들은 디미터라는 이름의 프로젝트를 진행하던 도중 객체지향 프로그래밍에서 객체들의 협력 경로를 제한하면 결합도를 효과적으로 낮출 수 있다는 사실을 알게 되어 디미터 법칙을 만들게 되었습니다.

디미터 법칙의 조건

아래의 내용는 오브젝트-조용호에서 나오는 내용입니다.

 

클래스가 특정한 조건을 만족하는 대상에게만 메시지를 전송하도록 프로그래밍해야한다. 모든 클래스 C와 C에 구현된 모든 메서드 M에 대해서, M이 메시지를 전송할 수 있는 모든 객체는 다음에 서술된 클래스의 인스턴스여야 한다. 이때 M에 의해 생성된 객체나 M이 호출하는 메서드에 의해 생성된 객체, 전역 변수로 선언 된 객체는 모두 M의 인자로 간주 한다.

  • M의 인자로 전달된 클래스(C 자체를 포함)
  • C의 인스턴스 변수의 클래스
  • 위 설명이 어렵다면 클래스 내부의 메서드가 아래의 조건을 만족하는 인스턴스에만 메시지를 전송하도록 프로그래밍해야 한다라고 이야하면 된다.
  • this 객체
  • 메서드의 매개변수
  • this의 속성
  • this의 속성인 컬렉션의 요소
  • 메서드 내에서 새엉된 지역 객체
디미터 법칙과 캡슐화
디미터 법칙은 캡슐화의 다른 관점에서 표현한 것입니다. 디미터 법칙이 가치있는 이유는 클래스를 캡슐화하기 위해 따라야 하는 구체적인 지침을 제공하기 때문입니다.
캡슐화 원칙이 클래스 내부의 구현을 감춰야 한다는 사실을 강조한다면 디미터 법칙은 협력하는 클래스의 캡슐화를 지키기 위해 접근해야 하는 요소를 제한합니다.
디미터 법칙은 협력과 구현이라는 사뭇 달라보이는 두 가지 문맥을 하나의 유기적인 개념으로 통합합니다. 클래스 내부 구현을 채워가는 동시에 현재 협력하고 있는 클래스에 관해서도 고민하도록 주의를 환기시키기 때문입니다.

기차 충돌

디미터 법칙을 설명 할 때 흔히 사용되는 예제 코드가 기차 충돌(train wreck)입니다.

디미터 법칙은 간단히 이야기하면 여러개의 .(dot)을 최대한 사용하지 말라는 법칙으로 말할 수 있습니다.

기차 충돌은 클래스의 내부 구현이 외부로 노출됐을때 나타나는 전형적인 형태로 메시지 전송자는 메시지 수신자의 내부 정보를 자세히 알게 됩니다.

 

아래는 디미터 법칙을 위반하는 코드의 예시입니다.

@Getter public class User { 
	private String email; 
	private String name; 
	private Address address; 
 } 

@Getter public class Address { 
	private String region; 
	private String details; 
 }

 

어떤 사용자가 서울에 살고 있으면 알림을 보내주는 메서드를 구현합니다.

@Service 
public class NotificationService { 
	public void sendMessageForSeoulUser(final User user) { 
            if("서울".equals(user.getAddress().getRegion())) { 
                sendNotification(user); 
		} 
	}
}

 

"서울".equals(user.getAddress().getRegion())

위 코드를 보면 User에서 Address를 찾고 getRegion으로 지역을 찾는 것을 볼 수 있습니다.

 

이는 User 객체에게 내부 구조를 물어보게 되는 것이고 내부 구조에 강하게 결합된다는 뜻입니다.

 

user.isSeoulUser()

 

위와 같이 내부 구조를 묻는 메시지가 아니라 수신자에게 무언가를 시키는 메시지로 만들어야 합니다.

 

묻지 말고 시켜라(Tell, Don't Ask)

절차적인 코드는 정보를 얻은 후에 결정한다. 객체지향 코드는 객체에게 그것을 시키도록 한다.