Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package kitchenpos.products.tobe.application;

import kitchenpos.menus.domain.Menu;
import kitchenpos.menus.domain.MenuProduct;
import kitchenpos.menus.domain.MenuRepository;
import kitchenpos.products.domain.Product;
import kitchenpos.products.domain.ProductRepository;
import kitchenpos.products.infra.PurgomalumClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.UUID;

@Service
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ν˜„μž¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 기동이 μ•ˆλ˜κ³ μžˆλŠ” 것 κ°™μ•„μš”.
λ‹€μŒ 리뷰 μš”μ²­ λ•ŒλŠ”, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ κΈ°λ™λ˜λŠ” μƒνƒœκ°€ λ˜λ„λ‘ν•΄μ£Όμ„Έμš”. πŸ˜ƒ

public class ProductService {
private final ProductRepository productRepository;
private final MenuRepository menuRepository;
private final PurgomalumClient purgomalumClient;

public ProductService(
final ProductRepository productRepository,
final MenuRepository menuRepository,
final PurgomalumClient purgomalumClient
) {
this.productRepository = productRepository;
this.menuRepository = menuRepository;
this.purgomalumClient = purgomalumClient;
}

@Transactional
public Product create(final Product request) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기쑴의 μ„œλΉ„μŠ€ λ‘œμ§μ„ μ‚¬μš©ν•˜λ˜ μœ„μΉ˜λ“€μ„ λ¦¬νŒ©ν„°λ§ν•œ λ‘œμ§λ“€μ„ λŒ€μ‹  μ‚¬μš©ν•˜λ„λ‘ λ³€κ²½ν•΄μ£Όμ„Έμš”.

μ§€κΈˆμ˜ μƒνƒœμ—μ„œλŠ” λ¦¬νŒ©ν„°λ§ν•œ μ½”λ“œλ“€μ΄ μ΄μ „μ²˜λŸΌ 잘 λ™μž‘ν• μ§€μ— λŒ€ν•œ 확신이 λ“€μ§€ μ•ŠλŠ”λ°μš”. πŸ€”
ν…ŒμŠ€νŠΈ μ½”λ“œ λ˜ν•œ λ³€κ²½λœ ProductService둜 λŒ€μ²΄ν•΄μ£Όμ‹  λ’€, ν…ŒμŠ€νŠΈ μ½”λ“œκ°€ 잘 λŒμ•„κ°€λŠ”μ§€ ν™•μΈμ΄λ˜λ©΄ 쒋을 것 κ°™μ•„μš”. πŸ˜ƒ

final BigDecimal price = request.getPrice();
if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException();
}
final String name = request.getName();
if (Objects.isNull(name) || purgomalumClient.containsProfanity(name)) {
throw new IllegalArgumentException();
}
Comment on lines +36 to +43
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Price, Name κ°’ 객체λ₯Ό μƒμ„±ν•˜κΈ°λ§Œν•΄λ„ 이 검증은 μžμ—°μŠ€λŸ½κ²Œ μˆ˜ν–‰λ  것 κ°™μ€λ°μš”. πŸ€”
두 κ°’ 객체λ₯Ό μƒμ„±ν•˜μ—¬ product의 μƒμ„±μž νŒŒλΌλ―Έν„°λ₯Ό 톡해 μ£Όμž…ν•΄μ„œ Product 객체λ₯Ό μƒμ„±ν•˜λ„λ‘ λ³€κ²½ν•΄λ³΄μ‹œλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€. πŸ˜‰

final Product product = new Product();
product.setId(UUID.randomUUID());
product.setName(name);
product.setPrice(price);
return productRepository.save(product);
}

@Transactional
public Product changePrice(final UUID productId, final Product request) {
final BigDecimal price = request.getPrice();
if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException();
}
final Product product = productRepository.findById(productId)
.orElseThrow(NoSuchElementException::new);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ˜ˆμ™Έκ°€ λ°œμƒν–ˆμ„ λ•Œ, μ μ ˆν•œ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό λ˜μ Έμ€€λ‹€λ©΄ μ—λŸ¬λ©”μ‹œμ§€λ₯Ό ν†΅ν•΄μ„œ 문제의 원인을 νŒŒμ•…ν•˜κΈ°κ°€ 더 μˆ˜μ›”ν•΄μ§€μ§€ μ•Šμ„κΉŒμš”? πŸ˜ƒ

Suggested change
.orElseThrow(NoSuchElementException::new);
.orElseThrow(() -> new NoSuchElementException("μƒν’ˆμ΄ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. productId: " + productId));

product.setPrice(price);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setterλ₯Ό μ΄μš©ν•˜κΈ°λ³΄λ‹€λŠ”, λ³€κ²½μ˜ 의미λ₯Ό λ“œλŸ¬λ‚Ό 수 μžˆλ„λ‘ 적절히 λ©”μ„œλ“œλͺ…을 넀이밍해보면 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€.

Suggested change
product.setPrice(price);
product.changePrice(price);

final List<Menu> menus = menuRepository.findAllByProductId(productId);
for (final Menu menu : menus) {
BigDecimal sum = BigDecimal.ZERO;
for (final MenuProduct menuProduct : menu.getMenuProducts()) {
sum = sum.add(
menuProduct.getProduct()
.getPrice()
.multiply(BigDecimal.valueOf(menuProduct.getQuantity()))
);
}
if (menu.getPrice().compareTo(sum) > 0) {
menu.setDisplayed(false);
}
}
return product;
}

@Transactional(readOnly = true)
public List<Product> findAll() {
return productRepository.findAll();
}
}
26 changes: 26 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package kitchenpos.products.tobe.domain;

import java.util.Objects;

import jakarta.persistence.Embeddable;
import kitchenpos.products.infra.PurgomalumClient;
@Embeddable
public class Name {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README.md에 적힌 μš©μ–΄ 사전, λͺ¨λΈλ§μ„ 봀을 λ•ŒλŠ” Name이 μ•„λ‹Œ DisplayedName으둜 μ •μ˜ν•΄μ•Όν•  것 κ°™μ€λ°μš”. πŸ€”
ν˜Ήμ‹œ 이전 λ―Έμ…˜ μ½”λ“œ or λ¬Έμ„œλ₯Ό κ°€μ§€κ³ μ™€μ•Όν•˜λŠ” 상황이라면 ν•΄λ‹Ή PR close ν›„, 0단계 PR을 μ˜¬λ €μ£Όμ„Έμš”!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name, Price의 경우 VO라고 λ³Ό 수 μžˆμ§€ μ•Šμ„κΉŒμš”? πŸ˜ƒ

private final String name;
private final PurgomalumClient purgomalumClient;

public Name(final String name, final PurgomalumClient purgomalumClient) {
this.purgomalumClient = Objects.requireNonNull(purgomalumClient, "purgomalumClient must not be null");
validate(name);
this.name = name;
}

private void validate(final String name) {
if (Objects.isNull(name) || name.isEmpty() || purgomalumClient.containsProfanity(name)) {
throw new IllegalArgumentException();
}
}
public String getName() {
return name;
}
}
24 changes: 24 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/Price.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.Embeddable;

import java.math.BigDecimal;
import java.util.Objects;
@Embeddable
public class Price {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μΆ”ν›„ λ‹€λ₯Έ μ»¨ν…μŠ€νŠΈμ—μ„œλ„ Priceκ°€ λ“±μž₯ν•  것 κ°™μ€λ°μš”.
λͺ¨λ‘ 같은 Priceλ₯Ό μ“°λŠ”κ±ΈκΉŒμš”? 그게 μ•„λ‹ˆλΌλ©΄ λ„€μ΄λ°μ μœΌλ‘œ ꡬ뢄을 ν•΄λ‘λŠ”κ²Œ μ’‹μ§€ μ•Šμ„κΉŒμš”? ex) ProductPrice

private final BigDecimal price;

public Price(BigDecimal price) {
validate(price);
this.price = price;
}

private void validate(final BigDecimal price) {
if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException();
}
}
public BigDecimal getPrice() {
return price;
}
}
34 changes: 34 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Id;
import kitchenpos.products.tobe.persistence.ProductEntity;

import java.util.UUID;

public class Product {
private final UUID id;

private final Name name;

private final Price price;

public Product(UUID id, Name name, Price price) {
this.id = id;
this.name = name;
this.price = price;
}

public UUID getId() {
return id;
}

public Name getName() {
return name;
}

public Price getPrice() {
return price;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kitchenpos.products.tobe.domain;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface ProductRepository {
Product save(Product product);

Optional<Product> findById(UUID id);

List<Product> findAll();

List<Product> findAllByIdIn(List<UUID> ids);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kitchenpos.products.tobe.persistence;

import kitchenpos.products.tobe.persistence.ProductEntity;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.UUID;

public interface JpaProductRepository extends JpaRepository<ProductEntity, UUID> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package kitchenpos.products.tobe.persistence;

import kitchenpos.products.tobe.domain.Product;
import kitchenpos.products.tobe.domain.ProductRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

@Repository
public class JpaProductRepositoryImpl implements ProductRepository {

private final JpaProductRepository jpaProductRepository;

public JpaProductRepositoryImpl(JpaProductRepository jpaProductRepository) {
this.jpaProductRepository = jpaProductRepository;
}

@Override
public Product save(Product product) {
ProductEntity productEntity = new ProductEntity(product);
return jpaProductRepository.save(productEntity).toDomain();
}

@Override
public Optional<Product> findById(UUID id) {
Optional<ProductEntity> productEntity = jpaProductRepository.findById(id);
return productEntity.map(ProductEntity::toDomain);
}

@Override
public List<Product> findAll() {
return jpaProductRepository.findAll()
.stream()
.map(ProductEntity::toDomain)
.collect(Collectors.toList());
}

@Override
public List<Product> findAllByIdIn(List<UUID> ids) {
return jpaProductRepository.findAllById(ids)
.stream()
.map(ProductEntity::toDomain)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package kitchenpos.products.tobe.persistence;

import jakarta.persistence.*;
import kitchenpos.products.tobe.domain.Name;
import kitchenpos.products.tobe.domain.Price;
import kitchenpos.products.tobe.domain.Product;
import java.util.UUID;

@Entity
@Table(name = "product")
public class ProductEntity {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

순수 도메인 객체와 JPA의 Entityλ₯Ό λΆ„λ¦¬ν•˜μ…¨κ΅°μš”? πŸ‘


@Id
@Column(name = "id", columnDefinition = "binary(16)")
private UUID id;

@Embedded
private Name name;

@Embedded
private Price price;

protected ProductEntity() {
}

public ProductEntity(Product product) {
this.id = product.getId();
this.name = product.getName();
this.price = product.getPrice();
}

public Product toDomain() {
return new Product(id, name, price);
}

public UUID getId() {
return id;
}

public Name getName() {
return name;
}

public Price getPrice() {
return price;
}
}