01 개방-폐쇄 원(ocp)
- 확장에 열려 있으며 수정에 닫혀 있다.
- 기존의 코드를 수정하지 않고도 애플리케이션의 동작을 확장할 수 있는 설계
컴파일타임 의존성을 고정시키고 런타임 의존성을 변경하라
- 컴파일 의존성을 수정하지 않고도 런타임 의존성을 쉽게 변경할 수 있다.
추상화가 핵심이다.
- 추상화에 의존하라!
- 추상화
- 핵심적인 부분만 남기고 불필요한 부분은 생략
- 생략된 부분을 문맥에 적합한 내용으로 채워넣음으로써 각 문맥에 적합하게 기능을 구체화하고 확장할 수 있다.
- 생략되지 않은 부분은 공통점 부분이다.(변하지 않는 부분)
- 추상화는 설계의 확장을 가능하게 한다.
- 추상화에서 가장 중요한 것은 변하는 것과 변하지 않는 것이 무엇인지를 이해하는 것이다.
02 생성 사용 분리
- 생성과 사용의 책임을 분리하자
- 가장 보편적인 방법은 객체를 생성할 책임을 클라이언트로 옮기는 것
FACTORTY 추가하기
- 클라이언트를 어떤한 컨텍스트에도 묶이지 않도록 객체 생성의 책임을 FACTORY(객체)로 이동
순수한 가공물에게 책임 할당하기
- FACTORY 클래스는 순수하게 기술적인 클래스
- 표현적 분해
- 도메인에 존재하는 사물 또는 개념을 표현하는 객체들을 이용해 시스템을 분해
- 도메인과 소프트웨어 사이의 표현적 차이를 최소화
- 행위적 분해
- 모든 책임을 도메인 객체에게 할당하면 여러가지 문제들이 발생할 수 있다.(낮은 응집도, 높은 결합도, 재사용성 저하)
- 이러한 문제를 해결하기 위해서는 임의로 만들어낸 가공의 객체에게 책임을 분산시켜야 한다.
- 임의로 만들어낸 가공의 객체 == PURE FABRICATION
- 도멘인의 본질적인 개념을 표현하는 추상화 → 인공적인 객체 이용
의존성 주입
- 의존선 주입
- 외부의 독립적인 객체가 인스턴스를 생성한 후 이를 전달해서 의존성을 해결하는 방법
- 외부에서 필요한 런타임 의존성을 전달 받을 수 있도록 만드는 방법을 포괄하는 명칭
- 의존성 주입 종류
- 생성자 주입
- setter 주입
- 메서드 주입
- 주입된 의존성이 한 두개 메서드에서만 사용된다면 각 메서드의 인자로 전달하는 것이 더 나은 방법일 수 있다.
숨겨진 의존성은 나쁘다
- SERVICE LOCATOR
- 객체들을 보관하는 일종의 저장소로 객체가 직접 SERVICE LOCATOR에게 의존성을 해결해줄 것을 요청하게 된다.
- 내부에 의존성을 감추고 있기에 비추
- 내부에 의존성을 숨기고 있는 경
- 의존성을 런타임에 반결하게 된다.
- 독립적인 단위 테스트 작성이 어려워진다.
- 캡슐화 박살(사용법을 이해하기 위해 구현 내부를 뒤면 캡슐화는 무너진 것이다.)
- 명시적인 의존성을 추구하라!
04 의존성 역전 원칙
추상화와 의존성 역전
- 협력의 본질은 상위 수준 클래스에 담겨 있다.
- 상위 수준 클래스가 하위 수준 클래스에 의존한다면 하위 수준의 변경에 의해 상위 수준 클래스가 영향을 받게 될 것이다.
- 상위 수준 클래스가 하위 수준 클래스에 의존해서는 안된다.
- 이러한 문제를 추상화를 통해 해결할 수 있다.
- 유연하고 재사용 가능한 설계를 원하다면 추상화를 따라야 한다.
- 의존성 역전 원칙
의존성 역전 원칙과 패키지
- 의존성 역전 원칙을 적용할 때 패키지 구조도 잘 생각해야 한다.
- 상위 수준 협력 흐름을 재사용하기 위해서는 추상화가 제공하는 인터페이스의 소유권 역전되어 있어야 한다.
- 인터페이스는 구현체들과 함께 배치시키는 것이 아니라 사용 객체와 함께 위치시켜야 한다.
05 유연성에 대한 조언
유연한 설계는 유연성이 필요할 때만 옳다
- 유연한 설계 == 복잡한 설계
- 유연성은 코드를 읽는 사람들이 복잡합을 수용할 수 있을 때만 가치가 있다.
협력과 책임이 중요하다
- 항상 역할, 책임, 협력에 우선적으로 초점을 맞추어라
- 객체 생성 메커니즘은 가장 나중의 일이다.