✔︎권장사항

- java 11

- IntelliJ

 

✔︎스프링부트 스타터에서 프젝 생성

https://start.spring.io/

 

시작하려고보니 자바 버전이 21 17밖에 없어서 버전을 먼저 맞추려고 한다.

 

✔︎설치되어 있는 모든 자바 버전 확인 

$ /usr/libexec/java_home -V

17이상이 없어서 업그레이드 해줘야 될 것 같음

✔︎java17 설치

https://www.oracle.com/java/technologies/downloads/#jdk17-mac

인텔이라 가장 아래거로 설치
설치 완

버전 확인 

$ java -version

 

✔︎프로젝트 생성 

 

✔︎파일구조 

기본일때
Compact일때

Compact패키지일때는 hello.core의 hello 폴더에 뭘 생성하기 어렵다고함  

 

인터페이스와 구현체를 같은 패키지에 두는 것보다는 따로 두는게 설계상 좋음

 

세번째 줄 MemberRepository에서 opt+enter 해줘서 얘네 생김

★자동완성

세미콜론까지 자동완성 시켜주는 단축키 : Command + Shift + Enter

public state void main 자동완성 : psvm

getter/setter 자동완성 : command + N

System.out.println 자동완성 : sout

 

이 상태에서 Member 쪽에 대고 command+option+v하면
이렇게 바뀜

✔︎return으로 주문결과 반환

src/main/java/hello.core/order/OrderService.java

 

src/main/java/hello.core/order/OrderApp.java

주문 도메인 전체에 대한 구현 완료

정액 할인 정책을 정률로 바꾸었을 때 클라이언트에 영향을 주지 않는지 역할이 잘 분리되었는지 확인 해볼 예정임

 

 


객체 지향 원리 적용

✔︎ 새로운 할인 정책 개발

core.discount.DiscountPolicy

package hello.core.discount;

import hello.core.member.Member;

public interface DiscountPolicy {

//    @return 할인 대상 금액
    int discount(Member member, int price);
}


core.discount.FixDiscountPolicy

package hello.core.discount;

import hello.core.member.Grade;
import hello.core.member.Member;

public class FixDiscountPolicy implements DiscountPolicy{

    private int discountFixAmount = 1000; //1000원 할인
    //VIP일경우 1000원 할인 아니면 할인x
    @Override
    public int discount(Member member, int price) {
        if (member.getGrade() == Grade.VIP){
            return discountFixAmount;
        } else {
        return 0;
        }
    }
}


core.discount.RateDiscountPolicy

package hello.core.discount;

import hello.core.member.Grade;
import hello.core.member.Member;

public class RateDiscountPolicy implements DiscountPolicy{

    private int discountPercent = 10;

    @Override
    public int discount(Member member, int price) {
        if(member.getGrade() == Grade.VIP){ //멤버등급이 vip일 경우
            return price * discountPercent / 100;
        } else {
            return 0;
        }
    }
}

 

✔︎ 새로운 할인 정책 적용과 문제점

- 적용시키기 위해서는 order.OrderServiceImpl 에서 적용시켜야함

 

order.OrderServiceImpl

- FixDiscountPolicy를 RateDiscountPolicy로 바꿔주어야 함 

package hello.core.order;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberrepository;

public class OrderServiceImpl implements OrderService{

    private final MemberRepository memberRepository = new MemoryMemberrepository();
    //private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        //member 찾음
        Member member = memberRepository.findById(memberId);
        //단일책임의 원칙 잘 지켜짐 할인정책에 문제가 있을때 할인정책만 수정 가능
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}

 

- 할인정책을 변경하기 위해서는 클라이언트인 OrderServiceImpl

단순히 DiscountPolicy에만 의존을 하고 있다고 알고 있었지만

OrderServiceImpl에서는 DiscountPolicy 뿐만 아니라 FixDiscountPolicy인 구체 클래스도 함께 의존하고 있다. → DIP 위반

#DIP(Dependency Inversion Principle) : 저수준 모듈이 고수준 모듈에 의존하게 되는 것

맞추기 위해서는 추상에만 의존하도록 변경해야함 (인터페이스에 의존)

 

기존의 이 코드에서 아래처럼 바꿔주어야 함

➜ 인터페이스에만 의존하도록 설계와 코드를 변경함

 

 

✔︎ 관심사의 분리

생성자를 만들어줌
여기서 MemberRepository는 추상화에만 의존 → DIP를 지키게 됨

AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를  생성자를 통해서 주입(연결)해준다.

 

- 설계 변경으로 `MemberServiceImpl` `MemoryMemberRepository` 를 의존하지 않는다! 단지 `MemberRepository` 인터페이스만 의존한다.

- MemberServiceImpl` 입장에서 생성자를 통해 어떤 구현 객체가 들어올지(주입될지)는 알 수 없다.

- MemberServiceImpl` 의 생성자를 통해서 어떤 구현 객체를 주입할지는 오직 외부( `AppConfig` )에서 결정된 다.

- MemberServiceImpl` 은 이제부터 **의존관계에 대한 고민은 외부**에 맡기고 **실행에만 집중**하면 된다.

 

core.MemberServiceImpl 기존의 이코드에서  

package hello.core.member;
//회원 서비스 구현체
public class MemberServiceImpl implements MemberService{

    //가입하고 찾으려면 memory레포가 있어야함 구현객체를 MemoryMemberRepository로 선택
    private final MemberRepository memberRepository = new MemoryMemberrepository(); //2. 여기서 할당이 됨
    //join에서 save를 호출하면 다형성에 의해서 Memory레포에 있는 save(오버라이드한개)가 호출됨
    public MemberServiceImpl(MemberRepository memberRepository){    //1. 여기서 memorymemberReposiotry가 들어와서
        this.memberRepository = memberRepository;
    }
    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

 이걸로 변경

package hello.core.member;
//회원 서비스 구현체
public class MemberServiceImpl implements MemberService{

    //가입하고 찾으려면 memory레포가 있어야함 구현객체를 MemoryMemberRepository로 선택
    private final MemberRepository memberRepository;
    //join에서 save를 호출하면 다형성에 의해서 Memory레포에 있는 save(오버라이드한개)가 호출됨
    public MemberServiceImpl(MemberRepository memberRepository){    //1. 여기서 memorymemberReposiotry가 들어와서
        this.memberRepository = memberRepository;
    }
    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

 

✔︎AppConfig 리팩터링

method명을 가지고옴으로써 역할이 다 드러남

→ 할인 정책을 변경해도 Appconfig 변경만으로 적용가능

 

 

스프링 컨테이너 적용

 

MemberApp.java

 

OrderApp.java

 

AppConfig.java

'개발 > spring' 카테고리의 다른 글

[스프링] 싱글톤 컨테이너  (0) 2024.04.26
[스프링] 스프링 컨테이너와 스프링 빈  (0) 2024.04.25
[스프링] 스프링 핵심 원리 - 기본편 1  (0) 2023.11.27
[스프링] start  (0) 2023.11.06

+ Recent posts