인프런 커뮤니티 질문&답변

sbean님의 프로필 이미지
sbean

작성한 질문수

스프링 핵심 원리 - 기본편

새로운 할인 정책 적용과 문제점

다른 요구사항에 대한 DiscountPolicy 설계 질문

해결된 질문

작성

·

188

0


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]
안녕하세요? 좋은 강의 감사한 마음으로 잘 듣고 있습니다. DiscountPolicy에 새로운 구현체를 추가하는 방법으로 유연하게 기능을 확장하는 예시를 잘 보았습니다. 그런 중 궁금한 점이, 지금 DiscountPolicy.discount 메서드는 Member형과 int형을 매개변수로 받고 있습니다.그런데 만약 다른 형의 자료가 필요한 discountPolicy를 만드려면 어떻게 설계하는 것이 좋을까요?예를 들어 itemName(String)을 기반으로 하는 할인 정책이 필요한 경우라면 어떻게 변경하는 것이 좋을지 궁금합니다. 제가 생각한 것은1) Generic DiscountPolicy 인터페이스를 만든다? public interface GenericDiscountPolicy<T> { int discount (T type, int price); } 2) 인터페이스 서명을 바꾼다?public interface DiscountPolicy { int discount (Member member, String itemName, int price); } 1) Generic으로 인터페이스를 만들면 interface를 사용하는 client에서 generic type을 지정해야 해서 다른 변경에 유연하지 않아 보입니다.2) 새로운 할인 정책 요소가 생길 때마다 매개 변수를 계속 늘리는 것은 바람직하지 않아 보입니다. 다형성을 이용한 유연한 설계라는 주제에 조금 벗어나는 것 같지만 유연하게 설계하기 위해 어떻게 객체지향 원리를 적용할 수 있는지 궁금합니다. 오늘도 좋은 하루 보내시길 바랍니다. 감사합니다! 🙏

답변 1

1

안녕하세요, 인프런 AI 인턴입니다.

sbean님의 질문에 대해 관련된 예시와 해결 방안이 담긴 기존 질문을 찾았습니다. 이는 ‘도메인 설계의 가정이 변경되었을 경우’라는 주제로, 비슷한 문제 상황에 직면한 다른 학습자의 사례와 그에 대한 답변을 포함하고 있습니다.

해당 사례에서는 할인 정책 도메인이 변경되었을 때의 상황에 대한 대응방안을 논의하고 있으며, 질문자와 유사하게 기존의 DiscountPolicy 설계를 어떻게 유연하게 변경할 수 있을지에 대해 고민하고 있습니다.

도메인 설계의 가정이 변경되었을 경우 질문에서는 다음 두 가지 방안에 대한 해결책이 제시되었습니다:

  1. 제네릭을 활용한 유연한 설계: 답변자는 DiscountPolicy 인터페이스를 제네릭 타입으로 변경하여 다양한 타입의 할인 조건을 유연하게 처리할 수 있는 방법을 제안합니다. 이 방식은 sbean님께서 고민하셨던 첫 번째 방안에 해당합니다. 다양한 할인 정책 (예: 회원 등급, 상품 정보 등)을 유연하게 처리할 수 있는 구조를 제공합니다.

  2. 매개 변수 확장: 질문자의 두 번째 고려사항과 같이, 인터페이스의 매개변수를 변경하여 새로운 할인 정책을 수용하는 방법에 대한 고민입니다. 답변에서는 이 방법보다는 제네릭을 활용하는 것이 더 유연한 설계를 가능하게 한다고 설명합니다.

이 사례는 sbean님의 고민에 대해 유용한 참고점을 제공할 수 있을 것 같습니다. 제네릭을 이용하여 DiscountPolicy 인터페이스의 유연성을 높이는 방법에 대해 자세히 설명하고 있으므로 주의 깊게 읽어보시길 추천드립니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

sbean님의 프로필 이미지
sbean
질문자

같은 부분에 대해 고민한 학습자들이 이미 있었군요! 연결해주신 답변도 도움 많이 되었습니다.

 

다만 처음 질문 시 궁금한 점에 대해 조금 더 답변해주시면 좋을 것 같습니다.

 

Generic을 사용해 구현할 경우 discountPolicy를 사용하는 client (예: OrderServiceImpl)에서 generic에 사용할 type을 넣어줘야 할텐데요,

 

이럴 경우 DIP가 잘 지켜질 수 있을지 궁금합니다.

DiscountPolicy<Item> discountPolicy; // GenericType을 어떻게 하는게 좋을까요?

DiscountPolicy<?>와 같이 하면 Object를 type 인자로 사용하게 되어 결국 캐스팅을 해야 하는 문제가 생기는 것 같습니다.

 

generic type을 client의 소스코드에 넣으면 discountPolicy가 변경될 때마다 client의 소스도 수정해야하는 문제가 생길 것 같습니다.

 

그럼 DiscountPolicy에 들어갈 수 있는 형을 제한해야 할까요?

public interface DiscountPolicy<T extends 할인적용가능요소>

 

어떤 좋은 방법이 있을지 궁금합니다.

 

감사합니다!

안녕하세요. sbean님, 공식 서포터즈 코즈위버입니다.

파라미터가 계속 늘어날 가능성이 있다면 아예 파라미터를 객체로 한 번 감싸서 전달하는 방법도 있습니다.

가령 아래와 같은 형태로 메서드를 만들어 둔다면, 파라미터를 추가해야 할 때마다 DiscountRequestDto 에 필드를 추가하면 되며, 클라이언트 코드에서는 오류가 발생하지 않습니다.

public int discount(DiscountRequestDto request);

 

다만 새로운 정책에 맞게 클라이언트 코드를 수정해야 하는데, 이 부분은 어쩔수 없는 수정으로 보입니다.

 

감사합니다.

sbean님의 프로필 이미지
sbean
질문자

제네릭 방법에 대해 코드로 작성해봤습니다만 한계가 있었습니다.

 

결국 제네릭은 컴파일 단계에서 타입 지정이 필요한데, DiscountPolicy를 제네릭으로 확장한다 해도 OrderServiceImpl에서 DiscountPolicy의 제네릭 타입을 컴파일 단계에서 정해줘야 하는 문제가 있습니다. (지정하지 않아도 컴파일 되나, raw type 경고가 표시됩니다.)

private final DiscountPolicy discountPolicy; // 타입을 지정하지 않으면 raw type 에러

private final DiscountPolicy<Member> discountPolicy; // Member형 지정을 하면 다른 타입을 넣을 수 없음.

DiscountPolicy 인터페이스 제네릭 타입에 와일드카드를 적용해도 결국 제네릭이 불공변하기때문에 적절한 해법이 되지 못했습니다.

 

제안해주신 DTO를 통한 파라미터 전달은 DTO 객체와 강한 결합이 불가피할 것 같습니다.

DiscountPolicy 구현체들은 결국 DTO의 getter를 통해서 필드에 접근해 값을 사용할 수 밖에 없기 때문에 그럴 것 같습니다. 이런 강한 결합은 불가피한 것일까요?

 

discount를 해야 하는 객체가 필요한 정보가 부족해서 생기는 어려움인 것 같은데,

discount 행동을 하는 주체를 바꿀 필요가 있을까요?

 

절대적인 정답은 없겠지만 다른 좋은 방법이 있을것 같아 계속 궁금함이 남습니다.

 

답변해주신 서포터즈님 감사합니다. 😄

sbean님의 프로필 이미지
sbean

작성한 질문수

질문하기