티스토리 뷰

- 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()로 바꿔주기만 하면 됨

댓글
최근에 올라온 글
최근에 달린 댓글
링크
Total
Today
Yesterday