@Service
@RequiredArgsConstructor
public class PaymentService {
private final PaymentRepository paymentRepository;
// private final FixDiscountPolicy fixDiscountPolicy; - 정책 변경으로 인한 코드 변경
private final PercentDiscountPolicy percentDiscountPolicy;
public void addHistory (long amount) {
// amount = fixDiscountPolicy.apply(amount); - 정책 변경으로 인한 코드 변경
amount = percentDiscountPolicy.apply(amount);
// 결제 내역 저장
paymentRepository.save(amount);
}
}
public class FixDiscountPolicy {
public long apply(long amount) {
if (amount >= 100000) {
return (long) (amount * 0.9);
} else if (amount >= 50000) {
return (long) (amount * 0.8);
}
return amount;
}
}
public class PercentDiscountPolicy {
public long apply(long amount) {
return (long) (amount * 0.9);
}
}
구현체에 의존시 다른 구현체로 바꿔야 될 때 기존 구현체에 해당하는 부분을 모두 바꿔줘야한다. 기존 구현체에 의존하는 부분이 많을 수록 변경 작업이 어려워진다.
의존 관계는 구현체가 아닌 인터페이스에 의존해야한다
@Service
@RequiredArgsConstructor
public class PaymentService {
private final PaymentRepository paymentRepository;
// 실제 적용될 정책은 외부에서 결정된다.
private final DiscountPolicy discountPolicy;
public void addHistory (long amount) {
amount = discountPolicy.apply(amount);
// 결제 내역 저장
paymentRepository.save(amount);
}
}
public interface DiscountPolicy {
long apply(long amount);
}
public class FixDiscountPolicy implements DiscountPolicy {
public long apply(long amount) {
if (amount >= 100000) {
return (long) (amount * 0.9);
} else if (amount >= 50000) {
return (long) (amount * 0.8);
}
return amount;
}
}
@Component
public class PercentDiscountPolicy implements DiscountPolicy {
public long apply(long amount) {
return (long) (amount * 0.9);
}
}
의존관계를 인터페이스에 의존하고 실제 사용할 구현체를 외부에서 결정하도록 위임함으로서 사용될 구현체에 상관없이 의존하는 쪽에서는 코드를 변경하지 않아도 된다.
스프링의 경우 런타임 시점에 구현체를 결정하여 생성하고 스프링 IoC 컨테이너를 통해 의존관계를 주입해준다.