의존관계 역전 법칙

  • Dependency Inversion Principle
  • 외부 모듈을 의존함에 있어 구현체에 의존하는 것이 아닌, 인터페이스에 의존해야 한다.

의존관계를 구현체에 의존하게 되면 변경이 어려워진다

@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 컨테이너를 통해 의존관계를 주입해준다.

+ Recent posts