상세 컨텐츠

본문 제목

5. 상품 도메인 개발

본문

객체 지향적인 설계

- 객체 지향적인 설계를 위해 entity 안에서 해결할 수 있는 로직은 entity 안에 넣어주는 게 좋음
- 데이터를 가지고 있는 쪽에 비즈니스 메서드가 있는게 좋음

- (기존에 하던 식으로, setter 이용하지 않기)

 

-> 아이템 엔티티의 재고 수량 늘리고 줄이는 로직을 아이템 엔티티 안에 작성

# Item Entity

package jpabook.jpashop.domain.item;

import jakarta.persistence.*;
import jpabook.jpashop.domain.Category;
import jpabook.jpashop.domain.OrderItem;
import jpabook.jpashop.domain.exception.NotEnoughStockException;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
@Getter @Setter
public abstract class Item {
    @Id @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;
    private int stockQuantity;

    @ManyToMany(mappedBy = "items")
    private List<Category> categories = new ArrayList<>();

    // == 비즈니스 로직 추가 ==
    // * 객체 지향적인 설계를 위해 entity 안에서 해결할 수 있는 로직은 entity 안에 넣어주는 게 좋음
    // * 데이터를 가지고 있는 쪽에 비즈니스 메서드가 있는게 좋음
    // 재고 수량 증가 로직
    public void addStock(int quantity) {
        this.stockQuantity += quantity;
    }

    public void removeStock(int quantity) {
        int restStock = this.stockQuantity - quantity;
        if (restStock < 0) {
            throw new NotEnoughStockException("need more stock");
        }
        this.stockQuantity = restStock;
    }
}

 

# ItemRepository

package jpabook.jpashop.repository;

import jakarta.persistence.EntityManager;
import jpabook.jpashop.domain.item.Item;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class ItemRepository {

    private final EntityManager em;

    public void save(Item item) {
        // item 은 저장할 때, 처음에 id 가 없음
        // 따라서 id 가 없다는 건, 완전히 새로 저장함을 의미
        if(item.getId() == null) {
            // 이 아이템을 신규로 등록
            em.persist(item);
        } else {
            // item 이 있다는 건, 이미 db 에 등록된 걸 db 에서 가져온 거
            // 따라서 여기에서의 save 는 update 와 유사
            // (merge 는 update 와 유사함)
            em.merge(item);
        }
    }

    // 단 건 조회를 할 땐 find 이용 가능
    public Item findOne(Long id) {
        return em.find(Item.class, id);
    }

    // 여러 개 찾을 땐, jpql 이용
    public List<Item> findAll() {
        return em.createQuery("select i from Item i", Item.class)
                .getResultList();
    }
}

 

# ItemService

package jpabook.jpashop.service;

import jpabook.jpashop.domain.item.Item;
import jpabook.jpashop.repository.ItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ItemService {
    private final ItemRepository itemRepository;

    // @Transactional 디폴트가 현재는 (readOnly = true) 로 설정해뒀으므로,
    // save 에서는 (readonly = false) 가 되도록, 이렇게 따로 적어줘야함 (여기서 적어준 게 우선권을 가짐)
    @Transactional
    public void saveItem(Item item) {
        itemRepository.save(item);
    }

    public List<Item> findItems() {
        return itemRepository.findAll();
    }

    public Item findItem(Long itemId) {
        return itemRepository.findOne(itemId);
    }

    // 현재 이 ItemRepository 는 위임만 하는 역할 수행
    // 경우에 따라서는, 이렇게 위임만 하는 경우 굳이 꼭 만들어야하나 고민해보자
    // 이런 경우엔, controller 에서 repository 에 바로 접근해서 써도 된다고 생각
}

 

'스프링 > [인프런] 실전! 스프링 부트와 JPA 활용1' 카테고리의 다른 글

7. 웹 계층 개발  (0) 2024.03.10
4. 회원 도메인 개발  (0) 2024.03.04
2. 도메인 분석 설계  (0) 2024.03.03
1. 환경 설정  (0) 2024.03.03

관련글 더보기