반응형
관심사의 분리
- 현재 주문에서는 할인 정책에 대한 것도 신경 쓰고 있다.
- 주문에 대한 책임 뿐만이 아니라 할인 정책을 정해야하는 책임도 가지고 있다.
- 주문은 주문과 관련된 역할을 수행하는 것에 집중해야하고 어떤 할인 정책이 적용되더라도 똑같이 주문할 수 있어야 한다.
- 할인 정책을 정하는 책임을 담당하는 별도의 책임자가 필요하다.
AppConfig 등장
- 애플리케이션의 전체 동작 방식을 구성(config)하기 위해, 구현 객체를 생성하고, 연결하는 책임을 가지는 클래스
public class AppConfig { //생성자 주입 public MemberService memberService() { return new MemberServiceImpl(new MemoryMemberRepository()); } //생성자 주입 public OrderService orderService() { return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy()); } }
- AppConfig는 애플리케이션의 실제 동작에 필요한 구현 객체를 생성한다.
- AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해서 주입(연결)해준다.
- MemberServiceImpl - 생성자 주입
public class MemberServiceImpl implements MemberService { private final MemberRepository memberRepository; public MemberServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } @Override public void join(Member member) { memberRepository.save(member); } @Override public Member findMember(Long memberId) { return memberRepository.findById(memberId); } }
- 관심사의 분리로 DIP도 만족하게 되었다.
MemberServiceImpl
의 생성자를 통해서 어떤 구현 객체를 주입할지는 오직 외부(AppConfig
)에서 결정된다.
- 의존관계에 대한 고민은 외부(
AppConfig
)에 맡기고 실행에만 집중하면 된다.
- 클래스 다이어그램
- 객체의 생성과 연결은 AppConfig 가 담당한다.
- DIP 완성: MemberServiceImpl 은 MemberRepository 인 추상에만 의존하면 된다. 이제 구체 클래스를 몰라도 된다.
- 관심사의 분리: 객체를 생성하고 연결하는 역할과 실행하는 역할이 명확히 분리되었다.
- 회원 객체 인스턴스 다이어그램
appConfig
객체는memoryMemberRepository
객체를 생성하고 그 참조값을memberServiceImpl
을 생성하면서 생성자로 전달한다.
- 클라이언트인
memberServiceImpl
입장에서 보면 의존관계를 마치 외부에서 주입해주는 것 같다고 해서 DI(Dependency Injection) 우리말로 의존관계 주입 또는 의존성 주입이라 한다.
- OrderServiceImpl - 생성자 주입
public class OrderServiceImpl implements OrderService { // private final MemberRepository memberRepository = new MemoryMemberRepository(); private final MemberRepository memberRepository; // 구현체 의존 제거 // private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); // private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); private final DiscountPolicy discountPolicy; // 구현체 의존 제거 public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; } @Override public Order createOrder(Long memberId, String itemName, int itemPrice) { Member member = memberRepository.findById(memberId); int discountPrice = discountPolicy.discount(member, itemPrice); return new Order(memberId, itemName, itemPrice, discountPrice); } }
- 관심사의 분리로 DIP도 만족하게 되었다.
OrderServiceImpl
입장에서 생성자를 통해 어떤 구현 객체가 들어올지(주입될지)는 알 수 없다.
OrderServiceImpl
의 생성자를 통해서 어떤 구현 객체을 주입할지는 오직 외부(AppConfig
)에서 결정한다.OrderServiceImpl
에는MemoryMemberRepository
,FixDiscountPolicy
객체의 의존관계가 주입된다.
- 의존관계에 대한 고민은 외부(
AppConfig
)에 맡기고 실행에만 집중하면 된다.
AppConfig 활용
- MemberApp
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
// MemberService memberService = new MemberServiceImpl();
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("find member = " + findMember.getName());
}
}
- OrderApp
public class OrderApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
OrderService orderService = appConfig.orderService();
// MemberService memberService = new MemberServiceImpl();
// OrderService orderService = new OrderServiceImpl();
Long memberId = 1L;
Member member = new Member(memberId, "memberA", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "itemA", 10000);
System.out.println("order = " + order);
System.out.println("order.calculatePrice = " + order.calculatePrice());
}
}
- 각 서비스 구현체 내부적으로 존재하는 의존 객체들이 초기에 주입됨으로써 DIP를 만족할 수 있게 되었다.
[참고자료]
반응형
'Java > Spring Framework' 카테고리의 다른 글
[스프링 핵심 원리 - 기본편] 스프링 빈 조회 (0) | 2021.08.14 |
---|---|
[스프링 핵심 원리 - 기본편] 스프링 핵심 원리 이해2 - 객체 지향 원리 적용(2) (0) | 2021.08.11 |
[스프링 핵심 원리 - 기본편] 스프링 핵심 원리 이해1 - 예제 만들기(2) (0) | 2021.08.10 |
[스프링 핵심 원리 - 기본편] 스프링 핵심 원리 이해1 - 예제 만들기(1) (0) | 2021.08.10 |
[스프링 핵심 원리 - 기본편] 좋은 객체 지향 설계의 5가지 원칙(SOLID) (0) | 2021.08.07 |