DIP 의존성 역전 원칙이 말하는 바

DIP 에서 말하는 ‘유연성이 극대화된 시스템’ 이란 소스 코드 의존성이 추상 에 의존하며 구체에는 의존하지 않는 시스템을 뜻한다.

그런 시스템을 위해 어떻게 설계를 해야 할까?

안정된 추상화

추상 인터페이스에 변경이 생기면 이를 구체화한 구현체들도 따라서 수정해야 한다. 반대로 구체적인 구현체에 변경이 생기더라도 그 구현체가 구현하는 인터페이스는 항상 , 좀 더 정확히 말하면 대다수의 경우 변경될 필요가 없다. ( 음… 그런가..? )

실제로 뛰어난 소프트웨어 설계자와 아키텍트라면 인터페이스의 변동성을 낮추기 위해 애쓴다.

인터페이스를 변경하지 않고도 구현체에 기느을 추가할 수 있는 방법을 찾기 위해 노력한다. 이는 소프트위어 설계의 기본이다.

즉 안정된 소프트웨어 아키텍처란 변동성이 큰 구현체에 의존하는 일은 지양하고 , 안정된 추상 인터페이스를 선호하는 아키텍처라는 뜻이다.

이 원칙에서 전달할려는 내용은 다음과 같이 매우 구체적인 코딩 실천법으로 요약할 수 있다.

구체적인 코딩 실천법

  1. 변동성이 큰 구체 클래스를 참조하지 말라. 대신 추상 인터페이스를 참조하라. 이 규칙은 언어가 정적이든 동적 타입이든 관계없이 모두 적용된다. 또한 이 규칙은 객체 생성 방식을 강하게 제약하며 , 일반적으로 추상 팩토리를 사용하도록 강제한다.
  2. 변동성이 큰 구체 클래스로부터 파생하지 말라. 이 규칙은 이전 규칙의 따름정리이지만 , 별도로 언급할 만한 가치가 있다. 정적 타입 언어에서 상속은 소스 코드에 존재하는 모든 관계 중에서 가장 강력한 동시에 뻣뻣해서 변경하기 어렵다. 따라서 상속은 아주 신중하게 사용해야 한다. 동적 타입 언어라면 문제가 덜 되지만 , 의존성을 가진다는 사실에는 변함이 없다. 따라서 신중에 신중을 거듭하는 게 가장 현명한 선택이다.
  3. 구체 함수를 오버라이드 하지 말라. 대체로 구체 함수는 소스 코드 의존성을 필요로 한다. 따라서 구체 함수를 오버라이드 하면 이러한 의존성을 제거할 수 없게 되며, 실제로는 그 의존성을 상속하게 된다. 이러한 의존성을 제거하려면, 차라리 추상 함수로 선언하고 구현체들에서 각자의 용도에 맞게 구현해야 한다.
  4. 구체적이며 변동성이 크다면 절대로 그 이름을 언급하지 말라. 사실 이 실천법은 DIP 원칙을 다른 방식으로 풀어쓴 것이다.

( 예..? 언급..언급..? 코딩에서 언급이란 무슨 뜻 이지..? )

Factory

해당 규칙들을 준수하려면 변동성이 큰 구체적인 객체는 특별히 주의해서 생성해야 한다.

사실상 모든 언어에서 객체를 생성하려면 해당 객체를 구체적으로 정의한 코드에 대해 소스 코드 의존성이 발생하기 때문이다.

그래서 이러한 문제를 해결하기 위해 추상 팩토리를 사용하곤 한다.

구체 컴포넌트