[Spring]基本編02.スプリングコアの原理1-作成例について


この文章はスプリングコア原理-プリミティブを聞いてまとめたものです.

📌 プロジェクトの設定

  • https://start.spring.io/は、GENERATEからダウンロードするように設定されます.
  • Intellijは[Open or Import]->ダウンロードした[core]フォルダ->buildにあります.Gradeを押して「Open」->「Open as Project」
  • をクリックします.
  • このコースでは、純粋なjavaのみを使用し、Dependenciesは選択しません.
  • IntellijIDEA->preference「gradle」と入力し、「build and runの使用」セクションと「Run testsの使用」セクションをgrade->IntellijIDEAに変換します.
  • Javaを実行するときにGradleを通過せずにIntellijで直接実行できるように設定すると、より高速になります.
  • 📌 メンバードメイン設計


    [会員ドメイン要件]
  • 会員登録と照会.
  • 会員は普通とVIPの2つの等級があります.
  • 会員データは、独自のDBを構築してもよいし、外部システムにバインドしてもよい.(未確定)
  • ドメイン協力関係は、計画者に見られます.
    これに基づいて,開発者は具体化においてクラス図を作成する.

  • 📌 メンバードメインの実行とテスト

  • Member.class
  • package hello.core.member;
    
    public class Member {
        private Long id;
        private String name;
        private Grade grade;
    
        public Member(Long id, String name, Grade grade) {
            this.id = id;
            this.name = name;
            this.grade = grade;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Grade getGrade() {
            return grade;
        }
    
        public void setGrade(Grade grade) {
            this.grade = grade;
        }
    }
    
  • Grade.enum
  • package hello.core.member;
    
    public enum Grade {
        BASIC,
        VIP
    }
    
  • MemberRepository.interface
  • package hello.core.member;
    
    public interface MemberRepository {
        void save(Member member);
        Member findById(Long memberId);
    }
    
  • MemoryMemberRepository.class
    (メモリ内のMemberRepository)
  • package hello.core.member;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class MemoryMemberRepository implements MemberRepository {
    
        private static Map<Long, Member> store = new HashMap<>();
    
    
        @Override
        public void save(Member member) {
            store.put(member.getId(),member);
        }
    
        @Override
        public Member findById(Long memberId) {
            return store.get(memberId);
        }
    }
    
  • MemberService.interface
  • package hello.core.member;
    
    public interface MemberService {
    
        void join(Member member);
        Member findMember(Long MemberId);
    
    }
    
  • MemberServiceImpl.class
  • package hello.core.member;
    
    public class MemberServiceImpl implements  MemberService{
    
        private final MemberRepository memberRepository = new MemoryMemberRepository();
        //memberRepository interface필요, but interface만 가지고 있으면 nullPointerException 터질것임.
    
        @Override
        public void join(Member member) {
            memberRepository.save(member);
    
        }
    
        @Override
        public Member findMember(Long memberId) {
            return memberRepository.findById(memberId);
        }
    }
    
  • MemberApp.class
  • package hello.core.member;
    
    public class MemberApp {
        public static void main(String[] args) {
            MemberService memberService = new MemberServiceImpl();
            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("findMember = "+findMember.getName());
        }
    }
    

    メンバーテストコードの作成


  • フォルダはmain、testフォルダに分かれており、後で構築して終了するとmain用のコードのみが表示され、test用のコードは構築時に失われます.

  • テストコードを作成する必要があります!

  • Testディレクトリにメンバーパッケージを作成し、作成します.
    -テストコードは、指定されたコード、whenコード、thenコードに分けられ、混同されません.
  • thenのAssistions.assertThatセクションで検証します.

  • MemberServiceTest.java
  • package hello.core.member;
    
    public class MemberServiceTest {
        
        MemberService memberService = new MemberServiceImpl();
        
        @Test // 이 어노테이션이 import 되어야 함.
        void join(){
            //givn - 멤버 생성
            Member member= new Member(1L, "memberA", Grade.VIP);
            
            //when - 멤버 회원가입하고, 그 멤버 찾음.
            memberService.join(member);
            Member findMember = memberService.findMember(2L);
            
            //then  //여기서 검증
            Assertions.assertThat(member).isEqualTo(findMember);
        }
    }
    

    📌 オーダーと割引ドメインの設計

  • オーダーおよび割引リスト
    -会員は商品を注文できます.
  • 会員等級に応じて割引政策を適用可能
  • 割引政策はすべてのVIPに1000元の固定金額割引を与えることを要求している.(後で変更される場合があります)
  • 割引政策が変わる可能性が高い.会社の基本的な割引政策はまだ確定していないので、開業前に延期したいという悩み.最悪の場合、割引は適用されない場合があります
  • オーダードメインコラボレーション、ロールおよび責任
  • オーダー生成:クライアントがオーダーの生成を要求します.
  • 会員照会:割引には会員等級が必要です.したがって、注文サービスは会員リポジトリで会員を検索します.
  • 適用割引:オーダー・サービスは、会員レベルに基づいて割引ポリシーを付与します.
  • 受注結果を返します.受注サービスは、割引結果を含む受注結果を返します.
  • ロールを作成し、インプリメンテーションを作成します.
  • つまり、役割をインプリメンテーションから分離して、インプリメンテーションオブジェクトを自由に組み立てることができます.
  • 会員リポジトリだけでなく、割引ポリシーも柔軟に変更できます.
    将来的に割引ポリシーが変更される場合は、割引ポリシーの一部を変更するだけです.

  • インタフェースのインプリメンテーションが1つしかない場合は、通常InterfaceImplと書きます->(インタフェース名)+(Impl)

  • 割引政策には固定割引政策と定率割引政策がある.
  • オブジェクト図はクラス図とは異なり、実際にnewを生成することによってオブジェクトを動的に関連付ける図である.
  • メモリで会員を検索し、定額割引政策(固定金額)をサポートしても注文サービスを変更する必要はありません.
    ->ロール間のコラボレーション関係を再利用できます.
  • メモリでメンバーを問い合わせるのではなく、実際のデータベースでメンバーを問い合わせる場合、オーダー金額に応じて%割引を行う正解率割引ポリシーをサポートしても、オーダー・サービスを変更する必要はありません.
    ->提携関係を再利用します.
  • 📌 オーダーと割引ドメインの実行とテスト


  • ディレクトリ構造は次のとおりです.


  • まずOrderパッケージを作成し、注文に関連するファイルを作成します.

  • Order Serviceの主な機能は、会員ID、商品名、商品価格を渡すことで注文を返す注文を生成することです.

  • Order.class
  • package hello.core.order;
    
    public class Order {
    
        private Long memberId;
        private String itemName;
        private int itemPrice;
        private int discountPrice;
    
        public Order(Long memberId, String itemName, int itemPrice, int discountPrice) {
            this.memberId = memberId;
            this.itemName = itemName;
            this.itemPrice = itemPrice;
            this.discountPrice = discountPrice;
        }
    
        public int calculatePrice(){ //할인 계산된 결과
            return itemPrice-discountPrice;
    
        }
    
        public Long getMemberId() {
            return memberId;
        }
    
        public void setMemberId(Long memberId) {
            this.memberId = memberId;
        }
    
        public String getItemName() {
            return itemName;
        }
    
        public void setItemName(String itemName) {
            this.itemName = itemName;
        }
    
        public int getItemPrice() {
            return itemPrice;
        }
    
        public void setItemPrice(int itemPrice) {
            this.itemPrice = itemPrice;
        }
    
        public int getDiscountPrice() {
            return discountPrice;
        }
    
        public void setDiscountPrice(int discountPrice) {
            this.discountPrice = discountPrice;
        }
    
        @Override
        public String toString() {
            return "Order{" +
                    "memberId=" + memberId +
                    ", itemName='" + itemName + '\'' +
                    ", itemPrice=" + itemPrice +
                    ", discountPrice=" + discountPrice +
                    '}';
        }
    }
    
  • OrderService.interface
  • package hello.core.order;
    
    public interface OrderService {
        Order createOrder(Long memberId, String itemName, int itemPrice);
        // 주문 생성할때, 회원id, 상품명, 상품 가격 넘김.
    }
  • OrderServiceImpl.class
  • 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 final MemberRepository memberRepository = new MemoryMemberRepository();
        private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    
        @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 );
        }
    
    }
  • デザインが良いと言えます.
    -orderserviceの立場から見ると、割引はわかりませんから.
    -割引は割引ポリシーによって決定されるため、単一責任の原則を遵守する必要があります.
    -ディスカウントを変更する必要がある場合は、オーダー・エンドではなく、ディスカウント・エンドを変更するだけです.
  • 割引パッケージの作成
  • DiscountPolicy.interface
  • package hello.core.discount;
    
    import hello.core.member.Member;
    
    public interface DiscountPolicy {
    
        /**
         * @return 할인 대상 금액
         */
        int discount(Member member, int price);
    }
  • FixDiscountPolicy.class
    -会員等級がVIPの場合1000元割引
  • package hello.core.discount;
    
    import hello.core.member.Grade;
    import hello.core.member.Member;
    
    public class FixDiscountPolicy implements DiscountPolicy{
    
        private int discountFixAmount=1000; //1000원 할인
    
        @Override
        public int discount(Member member, int price) {
            if(member.getGrade() == Grade.VIP){
                return discountFixAmount;
            }else{
                return 0;
            }
    
        }
    }
  • OrderApp.class
    -メンバーが作成されたら、接続して受注を作成し、受注情報と割引金額
  • を出力します.
    public class OrderApp {
        public static void main(String[] args) {
            MemberService memberService = new MemberServiceImpl();
            OrderService orderService= new OrderServiceImpl();
    
            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("order.calculatePrice= "+order.calculatePrice());
        }
    }

    Order TestCodeの作成


    TESTフォルダにOrderパッケージを作成し、作成
  • OrderServiceTest.class
  • public class OrderServiceTest {
    
        MemberService memberService = new MemberServiceImpl();
        OrderService orderService = new OrderServiceImpl();
    
        @Test
        void createOrder(){
            Long memberId = 1L;
            Member member = new Member(memberId, "memberA", Grade.VIP);
    
            memberService.join(member);
    
            Order order = orderService.createOrder(memberId, "itemA",10000);
            Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
        }
    }
  • 複数のテストを同時に実行しますか?
    ->メンバーパッケージとorderパッケージを含むhello.コアパッケージで実行します.