티스토리 뷰
- AppConfig.java를 추가하여 관심사 분리 / 이것도 순수 자바로만 구현
- 기존 MemberServiceImpl.java, OrderServiceImpl.java 에서는 인터페이스와 구현체 모두 의존하고 있어 DIP를 위반하고 있다
문제 : FixDiscountPolicy를 RateDiscountPolicy로 변경하는 순간 OrderServiceImpl의 소스 코드도 변경해야하는 번거로움이 있음
해결 : 이를 분리하기 위해 AppConfig를 만들어 수정
AppConfig.java / 애플리케이션 전체를 구성하기 위해 구현 객체를 생성하고 연결하는 책임을 가지는 별도의 설정 클래스
package com.hello.core;
import com.hello.core.Order.OrderService;
import com.hello.core.Order.OrderServiceImpl;
import com.hello.core.discount.FixDiscountPolicy;
import com.hello.core.member.MemberService;
import com.hello.core.member.MemberServiceImpl;
import com.hello.core.member.MemoryMemberRepository;
public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService(){
return new OrderServiceImpl(
new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
- AppConfig에서 MemberServiceImpl과 OrderServiceImpl에 필요한 객체를 생성하고 주입
MemberServiceImpl.java / 생성자 주입
package com.hello.core.member;
public class MemberServiceImpl implements MemberService {
// private final MemberRepository memberRepository = new MemoryMemberRepository();
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);
}
}
- MemoryMemberRepository에 대한 코드 없고 오직 MemberRepository 인터페이스에만 의존
- 추상화(memberRepository)에만 의존 -> DIP 지킴(o)
- 이제 MemberServiceImpl에서는 생성자를 통해 어떤 구현 객체가 들어올지 알 수 없게 됨 -> AppConfing에서 결정
- 클라이언트인 memberServiceImpl입장에서는 의존관계를 마치 외부에서 주입해주는거 같다고해서 DI(Dependency Injection 의존관계 주입)라고 부름
OrderServiceImpl / 생성자 주입
package com.hello.core.Order;
import com.hello.core.discount.DiscountPolicy;
import com.hello.core.member.Member;
import com.hello.core.member.MemberRepository;
public class OrderServiceImpl implements OrderService {
// private final MemberRepository memberRepository = new MemoryMemberRepository(); /// 회원찾기용
//private final DiscountPolicy discountPolicy = new FixDiscountPolicy(); ///고정할인정책
// private final DiscountPolicy = new RateDiscountPolicy();
/// FixDiscountPolicy에서 Rate로 수정되면 orderserviceImpl 도 수정해야함 ocp위반
/////////////////// DIP 지킴(인터페이스만 의존, 구현체에대해 전혀모름)
private final MemberRepository memberRepository; //final은 생성자 필수
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);
}
}
- OrderServiceImpl 또한 기존 인터페이스에도 의존, 구현체도 의존 - >DIP 위반
- 설계변경으로 더이상 FixDiscountPolicy에 의존 x
- 이제 OrderServiceImpl에서는 생성자를 통해 어떤 구현 객체가 들어올지 알 수 없게 됨 -> AppConfing에서 결정
MemberApp.java / AppConfig 사용
package com.hello.core;
import com.hello.core.member.Grade;
import com.hello.core.member.Member;
import com.hello.core.member.MemberService;
public class MemberApp {
public static void main(String[] args) {
///Appaonfig 사용
AppConfig appConfig = new AppConfig();
/// MemberService memberService = new MemberServiceImpl();
MemberService memberService = appConfig.memberService();
/// 멤버서비스 임플이 들어간거
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.java / Appconfig 사용
package com.hello.core;
import com.hello.core.Order.Order;
import com.hello.core.Order.OrderService;
import com.hello.core.member.Grade;
import com.hello.core.member.Member;
import com.hello.core.member.MemberService;
public class OrderApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
/// MemberService memberService = new MemberServiceImpl();
MemberService memberService = appConfig.memberService();
/// OrderService orderService = new OrderServiceImpl();
OrderService orderService = appConfig.orderService();
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("calculatePrice = " + order.calculatePrice());
}
}
정리
- AppConfig를 통해 관심사를 분리
- AppConfig를 공연기획자로 생각하고 배역에 맞는 담당 배우를 선택한다고 생각하면 됨(필요한 구체 클래스 선택)
리팩토링(Refactoring) : 외부동작을 바꾸지 않으면서 내부구조를 개선하는 것
(참고 : nesoy.github.io/articles/2018-05/Refactoring)
- 기존 AppConfig를 보면 중복이 있고 역할에 따른 구현이 잘 안보이는 점을 수정
- 할인정책 바꿔보기
AppConfig.java / 변경 전
package com.hello.core;
import com.hello.core.Order.OrderService;
import com.hello.core.Order.OrderServiceImpl;
import com.hello.core.discount.FixDiscountPolicy;
import com.hello.core.member.MemberService;
import com.hello.core.member.MemberServiceImpl;
import com.hello.core.member.MemoryMemberRepository;
public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(new MemoryMemberRepository());
}
public OrderService orderService(){
return new OrderServiceImpl(
new MemoryMemberRepository(), new FixDiscountPolicy());
}
}
AppConfig.java / 변경 후
package com.hello.core;
import com.hello.core.Order.OrderService;
import com.hello.core.Order.OrderServiceImpl;
import com.hello.core.discount.DiscountPolicy;
import com.hello.core.discount.RateDiscountPolicy;
import com.hello.core.member.MemberRepository;
import com.hello.core.member.MemberService;
import com.hello.core.member.MemberServiceImpl;
import com.hello.core.member.MemoryMemberRepository;
public class AppConfig {
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
public DiscountPolicy discountPolicy(){
///return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
- ctrl + alt + m : 메소드 생성
- new MemoryMemberRepository() 중복 제거
-할인정책은 AppConfig에서 return new FixDiscountPolicy()를 return new RateDiscountPolicy()로 바꿔주기만 하면 됨
'Spring' 카테고리의 다른 글
[Spring] 그냥 간단하게 로깅라이브러리 정리 - SLF4J (0) | 2022.02.08 |
---|---|
[Spring] 간단한 주문 시스템 예제4 - AppConfig 스프링 기반으로 변경 (0) | 2021.04.10 |
[Spring] 간단한 주문 시스템 예제2 - '주문','할인' 도메인 개발, 실행, 테스트 (0) | 2021.04.10 |
[Spring] 간단한 주문 시스템 예제 - '회원' 도메인 개발, 실행, 테스트 (0) | 2021.04.10 |
Spring 3 (0) | 2020.10.19 |
- Total
- Today
- Yesterday