인프런 커뮤니티 질문&답변
DiscountPolicy의 구현체에 관련 질문 드려요!
해결된 질문
작성
·
31
1
영호님 안녕하세요!!
[6-5. 설계 평가하기] 강의를 듣던 중 궁금한 부분이 생겨 질문을 드리게 되었습니다!
컴파일 타임 결합에서 런타임 결합으로 변경하는 과정에서 Movie 클래스의 calculateFee메서드와 DiscountPolicy 추상클래스의 getDiscountAmount 메서드가 Screening 객체에 의존하게 되는데
- Movie 클래스의 경우에는 Screening 객체를 직접 사용하는 것이 아닌 DiscountPolicy에 전달만 하고 있으며,
- DiscountPolicy를 상속받은 AmountDiscountPolicy 클래스의 경우에는 아예 Screening 객체를 사용하지 않고 있는 상황입니다!
Q. 혹시 이렇게 직접적으로 사용하지 않더라도, 메서드 파라미터로 정의해도 괜찮은 것인가요??
답변 2
1
테디베어님 안녕하세요
좋은 질문 남겨 주셔서 감사합니다. 🙂
Movie의 calculateFee 메서드와 DiscountPolicy의 getDiscountAmount 메서드는 서로 다른 이유로 Screening 객체에 의존하고 있습니다.
1. Movie 클래스가 Screening에 의존하는 이유
말씀하신 것처럼 이 경우는 DiscountPolicy가 금액을 계산하기 위해 Screening의 데이터가 필요하기 때문에 이 데이터를 전달하기 위해 의존성이 필요합니다.
만약 이 파라미터를 끊고 싶다면 아래와 같이 양방향 연관관계를 추가하는 방법이 있습니다.
아래 코드를 보시면 DiscountPolicy에 Movie에 대한 참조를 추가해서DiscountPolicy가 직접 Movie를 통해 Screening에 접근하고 있습니다.
public class Screening {
private Movie movie;
}
public class Movie {
private Money fee;
private DiscountPolicy discountPolicy;
**private Screening screening;
public void calculateDiscount() {
fee.minus(discountPolicy.calculateDiscount());
}**
}
public class DiscountPolicy {
private DiscountPolicy policy;
**private Movie movie; // Movie 참조 추가**
public Money calculateDiscount() {
for (DiscountCondition each : conditions) {
if (each.isSatisfiedBy(**movie.getScreening()**)) {
return getDiscountAmount(**movie.getScreening()**);
}
}
return Money.ZERO;
}
abstract protected Money getDiscountAmount(Screening screening);
}
이렇게 하면 Screening을 메서드의 파라미터로 전달할 필요가 없어지지만 아래 그림처럼 양방향 의존성이 추가되어 결합도가 높아집니다.
이렇게 바꾸더라도 여전히 Movie는 인스턴스 변수로 Screening을 포함하기 때문에 Movie에서 Screening에 대한 의존성을 제거할 수도 없습니다.
여기에서는 DiscountPolicy로 Screening을 전달해야하기 때문에 Movie에서 Screening으로의 의존성을 제거할 수는 없습니다.
대신 가장 결합도가 낮은 방식인 메서드 파리미터로 Screening을 전달하는 방식을 선택한 것입니다.
Screening 대신 값 객체를 전달해서 Screening에 대한 의존성을 완전히 제거하는 방법이 궁금하시면 아래 질문을 참조해 주시면 감사하겠습니다. 🙂
2. DiscountPolicy의 getDiscountAmount 메서드가 Screening에 의존하는 이유
getDiscountAmount 메서드는 자식 클래스들이 가격을 계산하기 위해 공통으로 의존하게 되는 메서드의 시그니처를 정의합니다.
이 경우에는 상속 계층에 속한 모든 자식 클래스들이 동일한 메서드를 오버라이딩해야 하기 때문에 다른 자식 클래스에서 필요하지 않더라도 특정한 자식 클래스가 필요로 한다면 동일한 객체를 전달할 수 밖에 없습니다.
이런 이유로 Screening을 전달한 것이죠.
위에서 링크로 달아놓은 값 객체를 전달하는 예제의 경우에는 getDiscountAmount 메서드에 Screening 대신 값 객체를 전달할거에요.
그런데 질문을 받고 코드를 보니 Screening대신 Movie를 전달하는게 결합도 측면에서 더 좋았을 것 같네요. 😂
답변이 되었는지 모르겠네요.
또 궁금한 부분 있으면 추가로 질문 남겨주시면 답변 드리겠습니다.
0
안녕하세요, 인프런 AI 인턴입니다.
테디베어님께서 질문하신 내용은 객체지향 설계에서 파라미터와 의존성 관리에 관한 중요한 부분입니다. 컴파일 타임 결합에서 런타임 결합으로 전환하면서 발생할 수 있는 의존성 문제를 잘 짚어주셨습니다.
메서드 파라미터 설정과 의존성
의존성 주입 및 관리:
Movie클래스의calculateFee메서드가Screening객체에 직접 의존하지 않고DiscountPolicy에 전달만 하는 경우, 이는 메서드 간의 데이터 흐름을 명확하게 하기 위한 방식입니다. 의존성이 낮아지면서 테스트가 용이하고, 변경에 따른 영향이 최소화되는 장점이 있습니다.
파라미터의 사용 여부:
AmountDiscountPolicy가Screening객체를 사용하지 않더라도, 메서드 파라미터로 정의하는 것은 설계 의도에 따라 정당화될 수 있습니다. 특히, 추상 클래스나 인터페이스를 구현하는 여러 클래스가 있을 때, 이러한 파라미터는 일관된 메서드 시그니처를 유지하게 해줍니다. 이는 클라이언트 코드가 다양한 구현체와 협력할 수 있도록 돕습니다.
일관성과 확장성:
- 다른
DiscountPolicy구현체가Screening객체를 사용할 수 있으며, 이를 통해 파라미터 일관성을 유지하면 클래스 간의 일관성 있는 협력이 가능합니다. 이는 객체지향 설계에서 미래 확장성을 고려한 접근법입니다.
- 다른
구현체에 따라 다르게 처리:
AmountDiscountPolicy가 어떤 이유로Screening객체를 사용하지 않더라도, 해당 객체가 필요한 상황이 올 수 있습니다. 따라서, 일관성을 위해 모든 구현체가 동일한 메서드 시그니처를 따르는 것이 더 안전할 수 있습니다.
이러한 방법은 객체지향 설계 원칙 중 하나인 개방-폐쇄 원칙(Open-Closed Principle)을 잘 따르는 사례입니다. 클래스가 추가적인 변경 없이 행동(혹은 기능)을 확장할 수 있는 구조를 지향하는 것이죠.
관련 질문들 및 주제 추가 정보
추상 클래스와 인터페이스의 파라미터 관리에 대한 구체적인 예제와 설명은 다음과 같은 관련 질문에서 찾아볼 수 있습니다:
- DiscountPolicy 구현 및 설계에 대해 궁금한 점이 있습니다.
- 이러한 논의는 다양한 설계 관점에서 이해할 수 있으며, 이는 시스템의 유연성과 미래 확장성을 높이는 것입니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있었습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.





답변 감사드립니다!
답변에서 설명해주신 다른 설계 방식들을 보면서, 사용하지는 않더라도 파라미터를 끊어내는 것이 오히려 결합도가 높아질 수 있다는 점을 확인할 수 있었습니다😓
설계의 트레이드 오프에 대해 다시 한 번 생각해볼 수 있었던 것 같아요!! 자세히 설명해주셔서 감사합니다!