전송자가 수신자의 내부 구조에 대해 물어보고 반환받은 요소에 대해 연쇄적으로 메시지를 전송한다.
기차 충돌(train wreck) -> 클래스의 내부 구현이 외부로 노출된 경우이다.
screening.getMovie().getDiscountConditions();
묻지 말고 시켜라(Tell, Don't Ask)
객체의 상태에 관해 묻지 말고 원하는 것을 시켜야 한다.
즉, 메시지 전송자가 수신자의 상태를 기반으로 결정을 내린 후 메시지 수신자의 상태를 바꿔서는 안 된다.
-> 자연스럽게 정보 전문가에게 책임을 할당
public class Audience {
public Long setTicket(Ticket ticket) {
if (bag.hasInvitation()) { //// 묻지 말고 시켜라 원칙 위배
...
} else {
...
}
}
}
public class Audience {
public Long setTicket(Ticket ticket) {
return bag.setTicket(ticket); // 묻지 말고 시켜라 원칙에 맞게 수정한 코드
}
}
의도를 드러내는 인터페이스
메서드가 어떻게 수행하느냐가 아니라 무엇을 하느냐에 초점을 맞추면 클라이언트의 관점에서 동일한 작업을 수행하는 메서드들을 하나의 타입 계층으로 묶을 수 있는 가능성이 커진다.
객체의 퍼블릭 인터페이스에 어떤 이름이 드러나야 하는지에 대한 지침을 제공함으로써 코드의 목적을 명확하게 커뮤니케이션할 수 있게 해 준다.
// 메서드가 작업을 어떻게 수행하는지
public class PeriodCondition {
public boolean isSatisfiedByPeriod(Screening screening) {...}
}
public class SequenceCondition {
public boolean isSatisfiedBySequence(Screening screening) {...}
}
public interface DiscountCondition { // 메서드가 무엇을 수행하는지
boolean isSatisfiedBy(Screening screening);
}
public class PeriodCondition implements DiscountCondition {
public boolean isSatisfiedBy(Screening screening) {...}
}
public class SequenceCondition implements DiscountCondition {
public boolean isSatisfiedBy(Screening screening) {...}
}
원칙의 함정
설계는 트레이드오프의 산물이다.
설계를 적절하게 트레이드오프 할 수 있는 능력이 숙련자와 초보자를 구분하는 가장 중요한 기준이다.
묻지 말고 시켜라와 디미터 법칙을 준수하는 것이 항상 긍정적인 결과로만 귀결되는 것은 아니다.
모든 상황에서 맹목적으로 위임 메서드를 추가하면 같은 퍼블릭 인터페이스 안에 어울리지 않는 오퍼레이션들이 공존하게 된다. -> 응집도가 낮아진다.
객체에게 시키는 것이 항상 가능한 것은 아니다.
가끔씩은 물어야 한다.
원칙을 맹신하지 마라.
명령-쿼리 분리 원칙
루틴(routine)
어떤 절차를 묶어 호출 가능하도록 이름을 부여한 기능 모듈
프로시저와 함수로 구분
프로시저(procedure)
정해진 절차에 따라 내부의 상태를 변경하는 루틴의 한 종류
부수효과를 발생시킬 수 있지만 값을 반환할 수 없다
함수(function)
절차에 따라 필요한 값을 계산해서 반환하는 루틴의 한 종류
값을 반환할 수 있지만 부수효과를 발생시킬 수 없다
명령(Command)
객체의 인터페이스 측면에서 프로시저를 부르는 또 다른 이름
객체의 상태를 수정하는 오퍼레이션
쿼리(Query)
객체의 인터페이스 측면에서 함수를 부르는 또 다른 이름
객체와 관련된 정보를 반환하는 오퍼레이션
명령-쿼리 분리(Command-Query Separation) 원칙
오퍼레이션은 부수효과(side effect)를 발생시키는 명령이거나 부수효과를 발생시키지 않는 쿼리 중 하나여야 한다
"질문이 답변을 수정해서는 안 된다"
쿼리는 객체의 상태를 변경하지 않기 때문에 몇 번이고 반복적으로 호출하더라도 상관이 없다.
-> 명령이 개입하지 않는 한 쿼리의 값은 변경되지 않는다.
->또한 쿼리들의 순서를 자유롭게 변경할 수도 있다.
부수효과를 가지는 명령으로부터 부수효과를 가지지 않는 쿼리를 명백하게 분리함으로써
제한적이나마 참조 투명성의 혜택을 누릴 수 있게 된다.
참조 투명성(referential transparency) : "어떤 표현식 e가 있을 때 e의 값으로 e가 나타나는 모든 위치를 교체하더라도 결과가 달라지지 않는 특성"