-
TIL 25일차 (2021.11.15)TIL(Today I Learned) 2021. 11. 15. 17:43
TIL(2021.11.15)(Today 25) ✔
변화에 대응하는 객체지향 설계(애자일 실행 관례)
- interface와 구현체의 분리
AppConfig 구현 (생성자 주입을 통한 관심사 분리)
- 구현체가 구현체에 의존하지 않도록 설정.
- 실제 동작에 필요한 "구현 객체를 생성"
- 생성한 객체 인스턴스의 참조를 "생성자를 통해 주입(연결)" 해준다.
- DI(Dependency Injection), 의존관계 주입
- "사용 영역"과 "구성 영역"의 분리
SRP(한 클래스는 하나의 책임)
- 클라이언트는 실행만, AppConfig를 통해 연결과 구성요소를 생성 ]
OCP(sw 확장에는 열려있으나 변경에는 닫혀있어야 한다.)
- 전제조건 : 다형성 + DIP
- 사용 영역과 구성 영역을 분리
- 그로 인해 구성 영역만 변경, 사용 영역은 변경하지 않으므로
- 확장에는 열려있고 변경에는 닫혀있음을 만족
DIP(의존관계 역전 원칙) 적용
- AppConfig에서 클라이언트 대신 객체 인스턴스를 생성해서 의존관계를 주입
- IOC
- Inversion Of Control
- 제어의 역전
- AppConfig가 등장한 이후 객체는 실행하는 역할만 담당
- AppConfig에서 생성과 연결을 모두 결정
- 프로그램 제어 흐름은 AppConfig가 가져간다.
- 이렇듯 프로그램 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전(IoC)라고 한다.
- 프레임워크 vs 라이브러리
- 프레임워크 : 내가 작성한 코드를 제어하고, 대신 실행함.(ex) Junit test)
- 라이브러리 : 내가 작성한 코드(호출)가 직접 제어의 흐름을 담당.(ex) xml, JSQL)
의존관계 주입(DI)
- 정적인 클래스 의존관계 or 동적인 객체(인스턴스) 의존 관계
- 정적인 클래스 의존관계 : 인터페이스와의 의존관계(ex) MemberRepository, DiscountPolicy), 실행하지 않아도 분석가능
- 동적인 클래스 의존관계 : 인터페이스 안에 변경 가능한 구현체와의 관계(ex) FixDiscountPolicy, RateDiscountPolicy ), 실행해야 분석 가능
- 정적인 클래스 의존관계는 변경하지 않고, 동적인 객체 의존 관계만을 변경할 수 있다.
- 정적인 클래스 의존관계 or 동적인 객체(인스턴스) 의존 관계
IoC container, DI container
- AppConfig 처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는것을 의미
- 주로 DI 컨테이너라고함
- 또는 어샘블러, 오브젝트 팩토리 등으로 불림
- springContainer 📌
ApplicationContext
= 스프링 컨테이너- spring DI
- @Bean, @Configuration
DIP 위반 예시 📌
//OrderServiceImpl public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository = new MemoryMemberRepository(); private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); // private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
- inteface인 DiscountPolicy 뿐만 아니라 구현체인 FixDiscountPolicy()에도 의존하고 있다.
- 이유 : FixDiscountPolicy에서 RateDiscountPolicy로 변경하려면 OrderServiceImpl를 변경해야하기 때문
- DIP, OCP 위반
- 해결방법 : client가 interface에만 의존할 수 있도록 설정해주면됨
DIP 위반 해결방안 📌
- 배우, 기획자, 역할 등 관심사를 분리
- AppConfig
- 애플리케이션 전체 동작을 config(설정)하기 위해, "구현 객체를 생성"하고, "연결"하는 책임을 가지는 별도의 설정 클래스를 만들자.
//MemberServiceImpl public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } }
//OrderServiceImpl public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } }
//AppConfig public class AppConfig { public MemberService memberService(){ return new MemberServiceImpl(new MemoryMemberRepository()); } public OrderService orderService(){ return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy()); } }
// MemberApp public class MemberApp { public static void main(String[] args) { /** * AppConfig 생성(의존 관계 결정) */ AppConfig appConfig = new AppConfig(); MemberService memberService = appConfig.memberService(); // MemberService memberService = new MemberServiceImpl(); } }
//OrderApp public class OrderApp { public static void main(String[] args) { /** * AppConfig 생성(의존 관계 결정) */ AppConfig appConfig = new AppConfig(); appConfig.orderService(); // MemberService memberService = new MemberServiceImpl(); // OrderService orderService = new OrderServiceImpl(); } }
- 어플리케이션에서 직접 구현체에 접근(의존)하지 않고, AppConfig에 접근하도록 설정
- 관심사 분리
- 각자 맡은 역할에만 충실하도록
- MemberServiceImple은 구현체에 직접 접근 x, interface만 접근, AppConfig로 설정
- Dependency Injection(DI)
AppConfig Refactoring 📌
//AppConfig public class AppConfig { public MemberService memberService(){ return new MemberServiceImpl(memberRepositiry()); } private MemberRepository memberRepositiry() { return new MemoryMemberRepository(); } public OrderService orderService(){ return new OrderServiceImpl(memberRepositiry(), discountPolicy()); } public DiscountPolicy discountPolicy(){ return new FixDiscountPolicy(); } }
- refactoring을 통해 역할을 명확하게 구분
- 중복 없는 구현체
- 역할과 구현체의 명확한 구분, 빠르게 파악 가능.
'TIL(Today I Learned)' 카테고리의 다른 글
TIL 27 (2021.11.17) (0) 2021.11.17 TIL(2021.11.16)(26일차) (0) 2021.11.16 TIL(24일차)(2021.11.14) (0) 2021.11.14 TIL(23일차)(2021.11.13) (0) 2021.11.13 TIL(22일차)(2021.11.12) (0) 2021.11.12