source: http://mi.codes/programming-principles-the-law-of-demeter-lod/
'디미터의 법칙'이라고도 불리는 최소 지식 원칙은 소프트웨어 개발 가이드라인 중 하나이다.
모듈들 사이의 결합도를 줄여 코드의 품질을 높이는 것에 그 목적이 있다.
최소 지식 원칙을 따르면, 객체 사이의 상호작용은 될 수 있으면 아주 가까운 "친구" 사이에서만 허용하는 것이 좋다.
즉 '최소 지식 원칙'이라는 디자인 원칙은 정말 친한 친구하고만 얘기하라는 뜻이다.
Class Boy {
..
public:
string ChooseDateCourse(Girl girl) {
if(girl.stomach.isEmpty())
return "Restaurant";
else
return "Theater";
}
...
};
위 코드에서는 Boy 객체가 Girl 객체에 의존하면서 동시에 Girl 객체의 Stomach 객체에 접근하고 있다. 이는 곧 Boy가 Girl과 Stomach의 구현을 모두 알아야한다는 부담으로 증가한다. 세 개의 모듈간 결합도가 증가된 셈이다.
결합도가 증가되면 다음과 하나의 모듈의 수정에 영향을 받는 정도가 커진다는 것이다.
예를 들어 Stomach 코드에서 단순 boolean형으로 반환하는 하는 것이 아닌, 배고픔의 정도로 int형으로 반환되도록 수정하면 Boy의 코드까지 수정이 이루어져야 한다.
결국 먼 관계라도 모듈에 수정이 있을 때마다 해당 모듈과 결합한 모듈도 수정이 필요하다는 것이다.
(또한 결합도가 높으면 모든 의존된 코드들을 끌어와야 하니 그만큼 모듈 재사용도 힘들다.)
이러한 문제점을 해결하는 근본적 방법은 한 모듈이 구현을 알아야 하는 다른 모듈들을 최대한 적게 유지하는 것이고, 최소 지식 원칙이 말하고자 하는 바이다.
여러 객체하고 인연을 맺는 것을 피할 수 있는 방법은 다음과 같다.
어떤 객체의 메서드는 다음과 같은 객체의 메서드만 호출하자는 것이다.
위 가이드라인을 적용하여 Boy 클래스 구현을 수정하면 다음과 같다.
class Boy {
...
public:
string ChooseDateCourse(Girl girl) {
// Girl 클래스 구현 시 Stomach에서 가져온 정보를 바탕으로(boolean이든 int형이든) 로직을 적용하여,
// Boy에서 요청하는 메시지(배고픈지 아닌지)에 일관된 답(boolean)을 하도록 구현해야 한다.
if(girl.isHungry()){
return "Restaurant";
else
return "Theater";
}
...
};
위 코드에서는 Boy 객체의 메서드가 매개변수의 메서드까지만 접근하도록 원칙을 준수하였다.
Girl 내부의 변경이 있어도 Boy는 영향을 받지 않도록 해야한다.
station으로부터 thermometer라는 객체를 받은 다음, 그 객체의 getTemperature() 메서드를 직접 호출.
다른 메서드 호출 결과로 리턴된 객체에 대해서 메서드 호출.
public float getTemp(){
Thermometer thermometer = station.getThermometer();
return thermometer.getTemperature();
}
최소 지식 원칙을 적용하여 Station 클래스에 thermometer에 요청을 해주는 메서드를 추가함. 의존해야 하는 클래스의 개수를 줄일 수 있다.
public float getTemp(){
return station.getTemperature();
}
최소 지식 원칙이 적용된 Car 클래스 예시 코드
public class Car {
Engine engine; // 클래스의 구성요소, 이 구성요소의 메서드는 호출 가능
// 기타 인스턴스 변수
public Car(){
// 엔진 초기화 처리
}
// 매개변수로 전달된 객체의 메서드를 호출 가능
public void start(Key key){ // 새로운 객체를 생성. 이 객체의 매서드 호출 가능
Doors doors = new Doors();
boolean authorized = key.turns();
if(authorized){
// Car 객체의 구성요소의 메서드
engine.start();
// 객체 내 메서드
updateDashboardDisplay();
// 직접 생성하거나 인스턴스를 만든 객체의 매서드
doors.lock();
}
}
public void updateDashboardDisplay(){
// 디스플레이 갱신
}
}