diff --git a/src/main/java/com/example/demo/model/Cart.java b/src/main/java/com/example/demo/model/Cart.java new file mode 100644 index 0000000..d640ab7 --- /dev/null +++ b/src/main/java/com/example/demo/model/Cart.java @@ -0,0 +1,64 @@ +package com.example.demo.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Cart { + + private List lineItems; + private int totalQuantity; + + public Cart(List lineItems) { + this.lineItems = new ArrayList<>(lineItems); + calculateTotalQuantity(); + } + + public List getLineItems() { + return Collections.unmodifiableList(lineItems); + } + + public int getTotalQuantity() { + return totalQuantity; + } + + public void addProduct(ProductId productId, ProductOption productOption, int quantity) { + + + LineItem lineItem = findLineItem(productId, productOption); + + if (lineItem != null) { + lineItem.addQuantity(quantity, productOption); + calculateTotalQuantity(); + checkValidQuantity(); + return; + } + + lineItem = new LineItem(productId, productOption, quantity); + lineItems.add(lineItem); + calculateTotalQuantity(); + checkValidQuantity(); + } + + public void checkValidQuantity() { + if (totalQuantity > 20) { + throw new IllegalArgumentException("담을수 있는 수량을 초과했습니다."); + } + } + + private void calculateTotalQuantity() { + this.totalQuantity = lineItems.stream() + .mapToInt(LineItem::getQuantity) + .sum(); + } + + + private LineItem findLineItem(ProductId productId, ProductOption productOption) { + return lineItems.stream() + .filter(lineItem -> + lineItem.isSameProduct(productId,productOption)) + .findFirst() + .orElse(null); + } + +} diff --git a/src/main/java/com/example/demo/model/LineItem.java b/src/main/java/com/example/demo/model/LineItem.java new file mode 100644 index 0000000..79204f8 --- /dev/null +++ b/src/main/java/com/example/demo/model/LineItem.java @@ -0,0 +1,35 @@ +package com.example.demo.model; + + +public class LineItem { + + private final LineItemId id; + private final ProductId productId; + private final ProductOption productOption; + + private int quantity; + + + public LineItem(ProductId productId, ProductOption productOption, int quantity) { + this.id = LineItemId.generate(); + this.productId = productId; + this.productOption = productOption; + this.quantity = quantity; + } + + public int getQuantity() { + return quantity; + } + + + public void addQuantity(int quantity, ProductOption productOption) { + if(!this.productOption.equals(productOption)) { + return; + } + this.quantity += quantity; + } + + public boolean isSameProduct(ProductId productId, ProductOption productOption) { + return this.productId.equals(productId) && this.productOption.equals(productOption); + } +} diff --git a/src/main/java/com/example/demo/model/LineItemId.java b/src/main/java/com/example/demo/model/LineItemId.java new file mode 100644 index 0000000..c0e1f57 --- /dev/null +++ b/src/main/java/com/example/demo/model/LineItemId.java @@ -0,0 +1,12 @@ +package com.example.demo.model; + +import java.util.UUID; + +public record LineItemId( + String id +) { + + public static LineItemId generate() { + return new LineItemId("lineItemId-" + UUID.randomUUID()); + } +} diff --git a/src/main/java/com/example/demo/model/Product.java b/src/main/java/com/example/demo/model/Product.java new file mode 100644 index 0000000..f0b49f1 --- /dev/null +++ b/src/main/java/com/example/demo/model/Product.java @@ -0,0 +1,34 @@ +package com.example.demo.model; + +public class Product { + + private ProductId id; + private String name; + private int price; + + public Product(ProductId id, String name, int price) { + this.id = id; + this.name = name; + this.price = price; + } + + public ProductId getId() { + return id; + } + + public String getName() { + return name; + } + + public int getPrice() { + return price; + } + + public void changePrice(int price) { + this.price = price; + } + + public void changeName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/example/demo/model/ProductId.java b/src/main/java/com/example/demo/model/ProductId.java new file mode 100644 index 0000000..4951e6b --- /dev/null +++ b/src/main/java/com/example/demo/model/ProductId.java @@ -0,0 +1,6 @@ +package com.example.demo.model; + +public record ProductId ( + String id +){ +} diff --git a/src/main/java/com/example/demo/model/ProductOption.java b/src/main/java/com/example/demo/model/ProductOption.java new file mode 100644 index 0000000..aa16fdb --- /dev/null +++ b/src/main/java/com/example/demo/model/ProductOption.java @@ -0,0 +1,7 @@ +package com.example.demo.model; + +public record ProductOption( + String color, + String size +) { +} diff --git a/src/test/java/com/example/demo/model/CartTest.java b/src/test/java/com/example/demo/model/CartTest.java new file mode 100644 index 0000000..972473e --- /dev/null +++ b/src/test/java/com/example/demo/model/CartTest.java @@ -0,0 +1,101 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CartTest { + + private Product product1; + private Product product2; + private ProductOption productOption1; + private ProductOption productOption2; + + @BeforeEach + void setUp() { + product1 = new Product(new ProductId("product-1"), "product #1", 5000); + product2 = new Product(new ProductId("product-2"), "product #2", 3000); + + productOption1 = new ProductOption("red", "M"); + productOption2 = new ProductOption("black", "L"); + } + + @Test + @DisplayName("빈 장바구니의 수량은 0이다.") + void cartTotalQuantityIsZero() { + Cart cart = new Cart(List.of()); + + assertThat(cart.getTotalQuantity()).isEqualTo(0); + } + + @Test + @DisplayName("빈 장바구니에 물건 추가하면 장바구니의 전체수량은 추가한 수량과 같다.") + void addProduct() { + Cart cart = new Cart(List.of()); + + int quantity = 1; + cart.addProduct(product1.getId(), productOption1, quantity); + + assertThat(cart.getTotalQuantity()).isEqualTo(quantity); + } + + @Test + @DisplayName("장바구니에 이미 있는 물건 추가하면 전체 수량은 이미 있던 수량과 새로 추가하는 수량의 합이다.") + void addExistingProduct() { + + int oldQuantity = 1; + Cart cart = new Cart(List.of( + createLineItem(product1, productOption1, oldQuantity) + )); + + int newQuantity = 1; + cart.addProduct(product1.getId(), productOption1, newQuantity); + + assertThat(cart.getLineItems()).hasSize(1); + assertThat(cart.getTotalQuantity()).isEqualTo(oldQuantity + newQuantity); + } + + @Test + @DisplayName("장바구니에 새로운 있는 물건 추가하면 전체 수량은 이미 있던 물건의 수량과 " + + "새로 추가하는 물건의 수량의 합이다.") + void addNewProduct() { + + int oldQuantity = 1; + Cart cart = new Cart(List.of( + createLineItem(product2, productOption2, oldQuantity) + )); + + int newQuantity = 1; + cart.addProduct(product1.getId(), productOption1, newQuantity); + + assertThat(cart.getLineItems()).hasSize(2); + assertThat(cart.getTotalQuantity()).isEqualTo(oldQuantity + newQuantity); + } + + @Test + @DisplayName("전체 장바구니의 수량이 20개가 넘어가면 예외가 발생한다.") + void totalQuantityCanNotOverLimit() { + Cart cart = new Cart(List.of( + createLineItem(product1, productOption1, 19) + )); + + int newQuantity = 5; + + assertThatThrownBy( + () -> cart.addProduct(product1.getId(), productOption1, newQuantity) + ).isInstanceOf(IllegalArgumentException.class); + + } + + + + private LineItem createLineItem(Product product, ProductOption productOption, int quantity) { + return new LineItem(product.getId(), productOption, quantity); + } + +} diff --git a/src/test/java/com/example/demo/model/LineItemIdTest.java b/src/test/java/com/example/demo/model/LineItemIdTest.java new file mode 100644 index 0000000..0883233 --- /dev/null +++ b/src/test/java/com/example/demo/model/LineItemIdTest.java @@ -0,0 +1,30 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class LineItemIdTest { + + @Test + @DisplayName("같은 값이면 같은 객체로 취급된다.") + void sameLineItemId() { + LineItemId id1 = new LineItemId("LineItem-1"); + LineItemId id2 = new LineItemId("LineItem-1"); + + assertThat(id1).isEqualTo(id2); + } + + @Test + @DisplayName("generate()를 사용하면 서로다른 아이디가 생성된다.") + void lineItemIdIsUnique() { + LineItemId id1 = LineItemId.generate(); + LineItemId id2 = LineItemId.generate(); + + assertThat(id1).isNotEqualTo(id2); + } + + +} diff --git a/src/test/java/com/example/demo/model/LineItemTest.java b/src/test/java/com/example/demo/model/LineItemTest.java new file mode 100644 index 0000000..659e53f --- /dev/null +++ b/src/test/java/com/example/demo/model/LineItemTest.java @@ -0,0 +1,42 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + + +class LineItemTest { + + @Test + @DisplayName("같은 상품과 옵션일 경우, 수량을 추가할 수 있어야 한다.") + void isSameProduct(){ + ProductId productId = new ProductId("productId"); + ProductOption productOption = new ProductOption("red", "M"); + int quantity = 1; + int delta = 5; + + LineItem lineItem = new LineItem(productId, productOption, quantity); + lineItem.addQuantity(delta, productOption); + + assertThat(lineItem.isSameProduct(productId, new ProductOption("red", "M"))).isTrue(); + assertThat(lineItem.getQuantity()).isEqualTo(quantity + delta); + + } + + @Test + @DisplayName("같은 상품이라도 옵션이 다르면, 수량은 추가되지 않는다.") + void sameProductAndDifferentOption(){ + ProductId productId = new ProductId("productId"); + ProductOption productOption = new ProductOption("red", "M"); + int quantity = 1; + int delta = 5; + LineItem lineItem = new LineItem(productId, productOption, quantity); + + ProductOption productOption2 = new ProductOption("black", "M"); + lineItem.addQuantity(delta, productOption2); + + assertThat(lineItem.isSameProduct(productId, productOption2)).isFalse(); + assertThat(lineItem.getQuantity()).isEqualTo(quantity); + } +} diff --git a/src/test/java/com/example/demo/model/ProductIdTest.java b/src/test/java/com/example/demo/model/ProductIdTest.java new file mode 100644 index 0000000..e8361fa --- /dev/null +++ b/src/test/java/com/example/demo/model/ProductIdTest.java @@ -0,0 +1,20 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class ProductIdTest { + + @Test + @DisplayName("같은 값이면 같은 객체로 취급된다.") + void sameProductId() { + ProductId id1 = new ProductId("productId-1"); + ProductId id2 = new ProductId("productId-1"); + + assertThat(id1).isEqualTo(id2); + } + +} diff --git a/src/test/java/com/example/demo/model/ProductOptionTest.java b/src/test/java/com/example/demo/model/ProductOptionTest.java new file mode 100644 index 0000000..9f148df --- /dev/null +++ b/src/test/java/com/example/demo/model/ProductOptionTest.java @@ -0,0 +1,28 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ProductOptionTest { + + @Test + @DisplayName("값이 같으면 같은 객체로 취급된다.") + void sameValue() { + ProductOption option1 = new ProductOption("red", "M"); + ProductOption option2 = new ProductOption("red", "M"); + + assertThat(option1).isEqualTo(option2); + } + + @Test + @DisplayName("값이 다르면 다른 객체로 취급된다.") + void differentValue() { + ProductOption option1 = new ProductOption("red", "M"); + ProductOption option2 = new ProductOption("black", "M"); + + assertThat(option1).isNotEqualTo(option2); + } + +} diff --git a/src/test/java/com/example/demo/model/ProductTest.java b/src/test/java/com/example/demo/model/ProductTest.java new file mode 100644 index 0000000..6838595 --- /dev/null +++ b/src/test/java/com/example/demo/model/ProductTest.java @@ -0,0 +1,34 @@ +package com.example.demo.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ProductTest { + + private Product product; + + @BeforeEach + void setUp() { + product = new Product(new ProductId("product-1"), "Product #1", 5000); + } + + @Test + void changeProductName(){ + + String newName = "NewProduct"; + product.changeName(newName); + + assertThat(product.getName()).isEqualTo(newName); + } + + @Test + void changeProductPrice(){ + int newPrice = 10000; + product.changePrice(newPrice); + + assertThat(product.getPrice()).isEqualTo(newPrice); + } + +}