/
의존성 역전 원칙(Dependency Inversion Principle, DIP)

의존성 역전 원칙(Dependency Inversion Principle, DIP)

**의존성 역전 원칙(Dependency Inversion Principle, DIP)**은 SOLID 원칙 중 하나로, 객체 지향 설계에서 의존성의 방향을 역전시켜 상위 모듈이 하위 모듈에 의존하지 않도록 만드는 설계 원칙입니다. 이를 통해 모듈 간의 결합도를 낮추고, 더 유연하고 확장 가능한 코드를 작성할 수 있습니다.


의존성 역전 원칙이란?

정의

  1. **고수준 모듈(High-level Module)**은 저수준 모듈(Low-level Module)에 의존해서는 안 된다.

    • 두 모듈 모두 **추상화(Abstraction)**에 의존해야 한다.

  2. **추상화(Abstraction)**는 세부 사항(Concrete Details)에 의존해서는 안 된다.

    • 세부 사항이 추상화에 의존해야 한다.


쉽게 이해하기

일반적인 의존 관계는 아래와 같습니다:

High-level Module(고수준 모듈) Low-level Module(저수준 모듈)

 

의존성 역전을 적용하면 이렇게 됩니다:

High-level Module(고수준 모듈) ----> Interface(추상화) Low-level Module(저수준 모듈) ---->

 

즉, 고수준 모듈과 저수준 모듈 모두 추상화에 의존하게 하여, 구현 세부 사항을 숨기고 모듈 간 결합도를 낮춥니다.


의존성 역전의 필요성

  1. 유연성 향상:

    • 코드가 구체적인 구현에 의존하지 않기 때문에, 구현을 변경하거나 확장하기 쉬워집니다.

  2. 테스트 용이성:

    • 추상화된 인터페이스를 사용하면 Mock 객체를 주입하여 단위 테스트를 쉽게 작성할 수 있습니다.

  3. 변경의 영향 최소화:

    • 구현 세부 사항이 변경되어도 추상화 인터페이스만 유지되면 고수준 모듈에 영향을 주지 않습니다.


예시: 의존성 역전 원칙 적용 전

문제:

  • PaymentService가 직접 BankPaymentProcessor라는 구체적인 클래스에 의존하고 있습니다.

  • PaymentService를 변경하려면 BankPaymentProcessor의 구현을 변경해야 합니다.

public class PaymentService { private BankPaymentProcessor paymentProcessor; public PaymentService() { this.paymentProcessor = new BankPaymentProcessor(); } public void processPayment() { paymentProcessor.process(); } } public class BankPaymentProcessor { public void process() { System.out.println("Processing payment via bank"); } }

 


예시: 의존성 역전 원칙 적용 후

해결:

  • PaymentService는 이제 PaymentProcessor라는 추상화된 인터페이스에 의존합니다.

  • BankPaymentProcessor와 같은 구체적인 구현체는 인터페이스를 구현합니다.

  • PaymentServiceBankPaymentProcessor와 같은 구현체의 변경에 영향을 받지 않습니다.

 

사용

 


의존성 역전 원칙의 실제 활용

  1. 헥사고날 아키텍처:

    • 고수준 모듈(애플리케이션 로직)은 추상화된 Port에 의존하고, 저수준 모듈(예: 데이터베이스, API)는 Port를 구현하는 Adapter로 동작.

  2. DI(Dependency Injection):

    • Spring Framework와 같은 DI 컨테이너를 통해 의존성을 주입받아, 고수준 모듈과 저수준 모듈 간 결합도를 낮춤.


의존성 역전의 효과

  • 결합도 감소: 코드가 구현 세부 사항에서 추상화로 의존성이 이동.

  • 확장성 증가: 새로운 구현체를 추가해도 기존 코드를 수정하지 않아도 됨.

  • 테스트 편의성: Mocking 등을 통해 독립적인 테스트 가능.

이 원칙은 특히 유지보수성과 확장성이 중요한 프로젝트에서 큰 가치를 발휘합니다. 😊