먼저 Inner Class 를 사용하여 1개의 Class 파일에서 상품을 등록하는 기능을 구현한다.

소스는 아래와 같다.

 

아래의 소스는 다음의 순서를 가진다.

  1. ProductService에 addProduct 라는 요청을 보낸다.
  2. ProductService에서는 Product를 생성하여, ProductPort에게 save 할 것을 명령한다.
  3. ProductPort의 구현체인 ProductAdapter에서 Memory나 DB로 저장을 한다.
package com.example.productorderservice.product;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;

class ProductServiceTest {
    private ProductService productService;
    private ProductPort productPort;
    private ProductRepository productRepository;

    @BeforeEach
    void setUp(){
        productRepository = new ProductRepository();
        productPort = new ProductAdapter(productRepository);
        productService = new ProductService(productPort);
    }

    @Test
    void 상품등록() {
        final String name ="상품명";
        final int price = 1000;
        final DiscountPolicy discountPolicy = DiscountPolicy.NONE;
        final AddProductRequest request = new AddProductRequest(name, price, discountPolicy);
        productService.addProduct(request);
    }

    private record AddProductRequest(String name, int price,
                                     DiscountPolicy discountPolicy) {

        private AddProductRequest {
            Assert.hasText(name, "상품명은 필수입니다.");
            Assert.isTrue(price > 0, "상품 가격은 0보다 커야 합니다.");
            Assert.notNull(discountPolicy, "할인 정책은 필수입니다.");
        }
    }

    private enum DiscountPolicy{
        NONE
    }


    private class ProductService {
        private final ProductPort productPort;

        private ProductService(ProductPort productPort) {
            this.productPort = productPort;
        }

        public void addProduct(final AddProductRequest request) {
            final Product product = new Product(request.name(), request.price(), request.discountPolicy());

            productPort.save(product);
        }
    }

    private class Product {
        private Long id;
        private final String name;
        private final int price;
        private final DiscountPolicy discountPolicy;

        public Product(final String name, int price, DiscountPolicy discountPolicy) {
            Assert.hasText(name,"상품명은 필수입니다.");
            Assert.isTrue(price>0, "상품 가격은 0보다 커야 합니다.");
            Assert.notNull(discountPolicy,"할인 정책은 필수입니다.");
            this.name = name;
            this.price = price;
            this.discountPolicy = discountPolicy;
        }

        public void assignId(final Long id) {
            this.id = id;
        }

        public Long getId() {
            return id;
        }
    }

    private interface ProductPort {
        void save(final Product product);
    }

    private class ProductAdapter implements ProductPort {
        private final ProductRepository  productRepository;

        private ProductAdapter(final ProductRepository productRepository) {
            this.productRepository = productRepository;
        }

        @Override
        public void save(final Product product){
            productRepository.save(product);
        }
    }

    private class ProductRepository {
        private Long sequence = 0L;
        private Map<Long, Product> persistence = new HashMap<>();

        public void save(final Product product){
            product.assignId(++sequence);
            persistence.put(product.getId(),product);
        }
    }
}

 

 

실행결과


기능이 정상적으로 동작하는 것을 확인하면 Inner Class 로 선언되어 있는 것들을 한단계 상위로 빼준다.

 

현재의 디렉토리 구조

 

Inner Class를 상위로 빼준 후 디렉토리 구조

소스는 아래 Git 참고 https://github.com/ShinHenry/product-order-service.git

 

출처 : 실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD

+ Recent posts