본문 바로가기
반응형
Spring

[Spring] 스프링 핵심 원리 - 기본편 > 섹션3. 스프링 핵심 원리 이해2 - 객체 지향 원리 적용

by brightGarden02 2024. 4. 8.

인프런 김영한 강사님의 [스프링 핵심 원리 - 기본편] 섹션3. 스프링 핵심 원리 이해2 - 객체 지향 원리 적용에 대한 요점 정리, 강의 외 추가 코드 작성을 하였다.

 

고객이 제품을 주문하고 할인을 받는 내용이다.

할인 정책 요구사항 변경이 생겼다. 기존 고정 할인에서 정률(%) 할인으로 변경 요구사항이다. 이 요구사항은 다시 고정 할인으로 되돌릴 수도 있다. 할인에 대해 명세가 확정되지 않았다는 것이다. 이러한 상황에서 어떻게 객체 지향적으로 다형성, OCP, DIP를 만족시킬 수 있을지를 중점적으로 볼 것이다.

 

 

 

주문 생성시 제품에 할인을 적용하는데 할인이 바뀔 수 있게 구현해야한다. DiscountPolicy 인터페이스를 만들고 구체 클래스인 FixDiscountPolicy(고정 할인), RateDiscountPolicy(정률 할인)를 만든다. 

 

 

 

OrderServiceImpl은 OrderService 인터페이스를 구현하고 DiscountPolicy 인터페이스를 알고 있다. 할인에 대해 구체 클래스에서 할인 로직을 실행하니 다형성은 만족한다. OCP, DIP를 만족시키기 위해서 OrderServiceImpl은 어떤 할인 정책이 적용될지 알지 못한다. 외부에서 의존관계를 주입해주는 AppConfig가 필요하다.

 

 

 

 AppConfig는 OrderServiceImpl 구체 클래스를 생성해서 필요한 할인 정책을 선택하고 주입해준다. DIP를 만족한다. 의존 관계를 외부에서 주입해준다.

이로 인해 할인 정책이 바뀔시 AppConfig 구성 영역 클래스만 수정하고 OrderServiceImpl 사용 영역은 코드를 수정하지 않아도 된다. OCP를 만족한다. 사용 영역의 코드 수정 없이 확장하는 코드 작성이 가능해진다.

 

 

 

강의 외 추가 코드 작성을 하였다.

public interface DiscountPolicy {
    int discountByGrade(MemberData memberData, int price);
}


public class FixDiscountPolicy implements DiscountPolicy {

    private final int vipDiscountPrice = 1000;
    @Override
    public int discountByGrade(MemberData memberData, int price) {
        if(memberData.getGrade() == Grade.VIP) {
            return vipDiscountPrice;
        } else {
            return 0;
        }
    }
}

public class RateDiscountPolicy implements DiscountPolicy {

    private final double rateDiscount = 0.1;
    @Override
    public int discountByGrade(MemberData memberData, int price) {
        if(memberData.getGrade() == Grade.VIP) {
            return (int) (price * rateDiscount);
        } else {
            return 0;
        }
    }
}

 

 

 

public interface OrderService {
    void create(OrderRequestDto orderRequestDto);
}

public class OrderServiceImpl implements OrderService{

    private final MemberDao memberDao;
    private final OrderRepository orderRepository;
    private final ItemDao itemDao;
    private final DiscountPolicy discountPolicy;

    public OrderServiceImpl(MemberDao memberDao
                            ,OrderRepository orderRepository
                            ,ItemDao itemDao
                            ,DiscountPolicy discountPolicy) {
        this.memberDao = memberDao;
        this.orderRepository = orderRepository;
        this.itemDao = itemDao;
        this.discountPolicy = discountPolicy;
    }

    @Override
    public void create(OrderRequestDto orderRequestDto){
        //회원 조회: 할인을 위해서는 회원 등급이 필요하다. 그래서 주문 서비스는 회원 저장소에서 회원을 조회한다.
        MemberData memberData = memberDao.findById(Long.parseLong((orderRequestDto.getMemberId())));

        ItemData itemData = itemDao.findById(Long.parseLong(orderRequestDto.getItemId()));
        
        //할인 적용: 주문 서비스는 회원 등급에 따른 할인 여부를 할인 정책에 위임한다.
        int discountPrice = discountPolicy.discountByGrade(memberData, itemData.getItemPrice());

        //주문 결과 반환: 주문 서비스는 할인 결과를 포함한 주문 결과를 반환한다.
        Order order = new Order(Long.parseLong(orderRequestDto.getMemberId()), itemData.getItemName(), itemData.getItemPrice(), discountPrice);

        orderRepository.save(order);
    }
}

 

 

 

public class AppConfig {

   
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }


    public OrderService orderService() {
        return new OrderServiceImpl(
                memberDao()
                ,orderRepository()
                ,itemDao()
                ,discountPolicy()
        );
    }

  
    public MemberRepository memberRepository() { return new MemoryMemberRepository(); }

   
    public MemberDao memberDao() { return new MemoryMemberDao(); }

   
    public OrderRepository orderRepository() {
        return new DiscountOrderRepository();
    }

   
    public ItemDao itemDao() { return new CarItemDao(); }

    
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
//        return new FixDiscountPolicy();
    }

   
    public ItemRepository itemRepository() { return new CarItemRepository(); }

}

 

 

 

참고: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

 

스프링 핵심 원리 - 기본편 | 김영한 - 인프런

김영한 | 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보

www.inflearn.com

 

댓글


반응형
반응형