1- AppConfig 활용
- 예시. 배우와 공연 기획자의 분리
- 인터페이스에 어떤 구현체가 들어갈지는 공연 기획자가 해야한다.
- AppConfig는 구현 객체를 생성하고 연결을 책임지는 별도의 클래스를 칭함
- 역할분리와 OCP 준수를 위해 생성자주입[ 생성자주입: 생성자를 통해 객체를 전달하는 것]
2- AppConfig의 역할
- 어플리케이션 동작에 필요한 실제 구현 객체 생성
- 생성한 인스턴스의 참조를 생성자를 통해 주입
- AppConfig 객체는 구현체의 객체를 생성하고 그 참조값을 또 다른 생성자(해당 구현체를 받아주는 생성자)로 전달함
- 이로 클라이언트 입장에서 의존관계가 외부에서 주입해주는 것다고 해서 DI(Dependency Injection : 의존관계 주입 또는 의존성 주입)라고 함
package hello.core;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
/**
* Application 전체를 구성하고 설정하는 역할
* - 로미오 줄리엣 공연 예시 중 기획자
* - 어플리케이션에 대한 환경 구성을 모두 이곳에서 함
*/
public class AppConfig {
// 생성자 주입: 생성자를 통해서 객체가 주입되는 것
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
package hello.core.order;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
public class OrderServiceImpl implements OrderService{
// private MemberRepository memberRepository = new MemoryMemberRepository();
// 기존 코드: DIP, OCP 원칙 위배
// private DiscountPolicy discountPolicy = new FixDiscountPolicy();
/*
변경 코드: DIP, OCP 준수하도록 변경
(1) 인터페이스의 변수만 선언 (구체화가 아닌 추상화에만 의존하도록) : DIP 준수
*/
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
/**
* 해당 설계가 잘된 이유: 단일 책임 원칙 (SRP)이 잘 지켜짐
* OrderService는 할인 정책에 대해 모름.
* 좀더 풀어서 이야기하자면, 주문쪽에서 굳이 할인 정책에 대해 확인하고 까보지 않아도됨.
*
* 그렇기에 할인이 수정이 이루어져도 주문은 수정할 필요가 없기에 단일 책임 원칙이 잘 지켜짐
*
* @param memberId
* @param itemName
* @param itemPrice
* @return
*/
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(member.getId(), itemName, itemPrice, discountPrice);
}
}
package hello.core.order;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
public class OrderServiceImpl implements OrderService{
// private MemberRepository memberRepository = new MemoryMemberRepository();
// 기존 코드: DIP, OCP 원칙 위배
// private DiscountPolicy discountPolicy = new FixDiscountPolicy();
/*
변경 코드: DIP, OCP 준수하도록 변경
(1) 인터페이스의 변수만 선언 (구체화가 아닌 추상화에만 의존하도록) : DIP 준수
(2) 생성자를 통해 철저한 DIP 준수
- 할인정책이 무엇이 들어오든 주문은 그 역할만 수행하면 됨
*/
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
/**
* 해당 설계가 잘된 이유: 단일 책임 원칙 (SRP)이 잘 지켜짐
* OrderService는 할인 정책에 대해 모름.
* 좀더 풀어서 이야기하자면, 주문쪽에서 굳이 할인 정책에 대해 확인하고 까보지 않아도됨.
*
* 그렇기에 할인이 수정이 이루어져도 주문은 수정할 필요가 없기에 단일 책임 원칙이 잘 지켜짐
*
* @param memberId
* @param itemName
* @param itemPrice
* @return
*/
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(member.getId(), itemName, itemPrice, discountPrice);
}
}
3- AppConfig 활용 예시
package hello.core;
import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
//MemberService memberService = new MemberServiceImpl();
// (코드 수정) DIP 원칙 적용된 memberService를 받아옴
MemberService memberService = appConfig.memberService(); // 여기엔 할당된 MemberServiceImple 구현 객첵 할당됨
// command + option + v
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());
}
}
'Development > Spring Boot' 카테고리의 다른 글
[Spring Boot] 새로운 구조 및 구현체 적용 (0) | 2022.08.04 |
---|---|
[Spring Boot] AppConfig 리팩토링 (0) | 2022.08.04 |
[Spring Boot] 주문과 할인 도메인 설계 (3-1) 주문과 할인 도메인 개발 (0) | 2022.08.01 |
[Spring Boot] 주문과 할인 도메인 설계 (3) (0) | 2022.08.01 |
[Spring Boot] 비즈니스 요구사항과 설계 (2-2) 회원 도메인 실행 및 테스트 (0) | 2022.08.01 |