ObjectOrientedProgramming의 Design Principle의 한가지. A fundamental principle of object oriented design that states concrete classes should not be directly depended upon. That rather, the bulk of the code in the system should depend only upon the interfaces that those concrete classes implement.
DependencyInversion은 ObjectOrientedProgramming의 가장 중요한 특성이라고 해도 과언이 아닙니다. RobertCecilMartin은 AgileSoftwareDevelopmentPpp에서 "It doesn't matter what language a program is written in. If its dependencies are inverted, it has an OO design. If its dependencies are not inverted, it has a procedural design"이라고 말한 바 있습니다.
--AlanKang
UmlForJavaProgrammers 제6장 "OOD의 원칙" 중에서.
UML Diagram을 통해 DIP Violation 찾아내기:
UML을 사용하면 이 원칙을 지키는지 매우 쉽게 검사할 수 있다. UML 다이어그램의 화살표마다 따라가서 모두 인터페이스나 추상 클래스를 가리키는지 확인하면 된다. 만약 Concrete Class에 의존하는데 그 클래스가 자주 변경된다면, DIP를 어기는 것이며 따라서 시스템도 변화에 민감하게 되어 버릴 것이다.--p141
DependencyInversion은 CircularDependency를 풀어주는 마술같은 트릭의 원천입니다. 가장 일반적인 사례는 다음과 같습니다:
before: A <----> B after: C <------+ ^ | | | | | A -----> B
여기에서 C는 Abstract type, A에서 C로 가는 화살표는 Generalization. 나머지 화살표는 일반적인 Dependency 입니다. ( ASCII-art의 한계 --;; )
--강규영
이 원칙을 ExtremeProgramming의 프랙티스에도 적용할 수 있겠다는 생각이 들었습니다. 예를 들어 Refactoring을 하려면 UnitTest가 꼼꼼하게 붙어있어야 합니다. 그래야 코드의 외적 행위가 유지되고 있다는걸 확신할 수 있기 때문이죠. 그런데, UnitTest를 꼼꼼하게 붙이려면 기존 코드를 테스트하기 쉽도록 Refactoring 해야할 필요가 있습니다. 그래서 애초부터 TestDrivenDevelopment로 개발된 코드가 아니라면, 두 실천법 사이에 일종의 CircularDependency가 생기게 됩니다.
이 문제의 해법은 DIP를 적용하여 CircularDependency를 끊는 것입니다. Refactoring이라는 프랙티스( B )보다 좀 더 추상적인 뭔가를 만들고( IB ), UnitTest라는 프랙티스( A )가 그것( IB )에 의존하게 바꾸는 것이죠. Refactoring을 일반화(generalization)한 다른 프랙티스를 통해 UnitTest를 하기 용이한 코드를 얻어내는 것입니다. 이와 관련된 여러가지 팁들이 WorkingEffectivelyWithLegacyCode 같은 책에 소개되어 있죠.
이런 생각을 이번(Year2006) 자바컨퍼런스에서 간단히 언급했었는데, 전달이 잘 되었는지 약간 의문입니다.