03 설계원칙 -2
10장 ISP: 인터페이스 분리 원칙 The Inteface Segregation Principle
다수의 사용자가 OPS 클래스의 오퍼레이션을 사용.
이런 의존성으로 OPS 클래스에서 op2 소스코드가 변경되면 User1도 다시 컴파일한 후 배포해야함.
오퍼레이션을 인터페이스 단위로 분리하여 해결.
ISP와 언어
정적타입 언어의 경우 include 선언문으로 소스코드 의존성이 발생함.
동적타입 언어는 선언문이 존재하지 않고 런타임에 추론이 발생.
따라서 소스코드 의존성이 존재하지 않아 유연하고 결합도가 낮은 시스템을 만들 수 있음.
ISP와 아키텍처
필요이상으로 많은걸 포함하는 모듈에 의존하는 것은 해로움. 불필요한 재컴파일과 재배포를 강제하기 때문.
결론
불필요한 짐을 실은 무언가에 의존하면 예상못한 문제에 빠짐.
11장 DIP: 의존성 역전 원칙 The Dependency Inversijon Principle
유연성이 극대화된 시스템이란
소스코드 의존성이 추상 abstraction에 의존하며 구체 concretion에는 의존하지 않는 시스템
정적타입의 경우 use, import, include 구문은 오직 인터페이스나 추상클래스 같은 추상적인 선언만을 참조해야 한다는 뜻.
동적차입의 경우에도 구체 모듈을 참조해서는 안된다는 것.
하지만 안정적인 구체클래스의 경우나 안정성이 보장되는 환경에서는 대개 무시해도 됨.
의존을 피하고자하는 대상은 변동성이 큰 volatile 구체 요소.
안정된 추상화
인터페이스는 구현체보다 변동성이 낮다.
설계의 기본은 인터페이스를 변경하지 않고도 구현체에 기능을 찾는 방법.
안정된 추상 인터페이스를 선호하는 아키텍처가 바람직.
- 변동성이 큰 구체 클래스를 참조하지 말라.
- 일반적으로 추상 팩토리 abstract factory 사용을 강제. - 변동성이 큰 구체클래스로부터 파생하지 말라.
- 상속은 신중하게 사용. - 구체 함수를 오버라이드하지 말라.
- 추상함수로 선언하고 ㄱ혀체들에서 각자의 용도에 맞게 구현. - 구체적이며 변동성이 크면 절대로 그 이름을 언급하지 말라.
팩토리
변동성이 큰 구체 객에는 주의해서 생성.
ConcreteImpl에 대해 소스코드 의존성을 만들지 않기 위해 Application은 ServiceFactory 인터페이스의 makeSvc 메서드 호출.
이 메서드는 Impl에서 구현. 그리고 ServiceFactoryImpl 구현체가 ConcreateImpl 인스턴스 생성 후 Service 타입으로 반환.
붉은 곡선은 아키텍처 경계를 뜻함.
소스코드 의존성은 해당 곡선과 교차할 때 추상적인 쪽을 향한다.
추상컴포넌트는 업무규칙을 포함하고,
구체컴포넌트는 필요 세부사항을 포함함.
제어흐름은 의존성과는 정반대 방향.
소스코드 의존성은 제어흐름과는 반대 방향으로 역전된다.
따라서 이를 의존성 역전 Dependency Inversion 이라 부름.
구체 컴포넌트
DIP 위배를 모두 없앨수는 없다.
하지만 클래스들을 구체 컴포넌트 내부로 모을수 있고 시스템의 부분으로 분리할 수 있다.
이 컴포넌트를 메인 Main 이라 부른다. (main 함수를 포함하기에)
main함수는 ServiceFactoryImpl 인스턴스를 생성 후, 이 인스턴스를 ServiceFactory 타입으로 전역변수에 저장.
그러면 Application은 전역 변수를 이용해 ServiceFactoryImpl 인스턴스에 접근 할 것.
결론
DIP는 아키텍처 다이어그램에서 계속해서 등장하고 눈에 드러나는 원칙.
의존성은 더 추상적인 엔티티로 향하는데 이러한 규칙은 의존성 규칙 Dependency Rule 이라함