[WIL] - Java 커머스 과제

2026. 1. 16. 13:16·IL/WIL

 

저번 과제에서는 어떻게 시작해야 될지도 모르고 단계별로 차근차근 못했는데 이번에는 단계별로 차근차근 해 볼 생각이다.

 


🚩STEP 1 - 객체지향 설계를 적용해 상품 관리 시스템을 프로그래밍 해 보자

1️⃣ `product` 클래스 생성하기

// 상품 1개의 정보를 담는 클래스(설계도)
public class Product {
    
    // 필드 - 이 객체가 가지고 있어야 하는 정보를 저장하는 변수
    String name;        // 상품명
    int price;          // 가격
    String descrption;  // 설명
    int stock;          // 재고 수량


    // 생성자
    public Product(String name, int price, String descrption, int stock) {
        this.name = name;
        this.price = price;
        this.descrption = descrption;
        this.stock = stock;
    }

}

1) 클래스(class) = 설계도

  • `product` 클래스는 상품 하나가 어떤 정보를 가져야 하는지 정의한 설계도
  • 이 설계도를 기반으로 실체 상품을 만들면 그게 객체

2) 객체(object) = 실제 만들어진 상품

3) 필드(field) = 객체의 데이터

  • 여기서는 `name`, `price`, `description`, `stock` 이 상품이 무슨 상품인지 설명

4) 생성자(constructor) = 객체 만들 때 최초 세팅을 담당한다

  • 생성자는 클래스 이름이랑 똑같다
  • 반환 타입이 없다 (`void`가 안 붙음)
  • `new Product()` 할 때 자동 실행된다

 

 

 

2️⃣ `main` 함수에서 `Product` 클래스를 생성하여 상품 목록을 추가

상품은 여러 개가 있어야 목록이 된다
-> 그 여러 개의 `Product`를 어디에 담아야 되는가?
-> `List` 순서가 있고 개수 늘어날 수 있다
public class Main {
    public static void main(String[] args) {

        // 프로그램 시작 출력
        System.out.println("[ 실시간 커머스 플랫폼 - 전자제품]");

        // 여러 Product를 담기 위한 List 생성
        List<Product> products = new ArrayList<>();

        // Product 객체 생성을 하고 List에 추가한다
        // new Produc()를 이용해서 실제 상품 객체를 생성한다
        products.add(new Product("Galaxy S25", 1200000, "최신 안드로이드 스마트폰", 50));
        products.add(new Product("iPhone 16", 1350000, "Apple의 최신 스마트폰", 30));
        products.add(new Product("MacBook Pro", 2400000, "M3 칩셋이 탑재된 노트북", 20));
        products.add(new Product("AirPods Pro", 350000, "노이즈 캔슬링 무선 이어폰", 100));
    }
}

1) `List<Product>`

  • `List` = 여러 개를 담는 통
  • `<Product>` = 이 리스트에는 Product만 담겠다는 약속 (제네릭)

2) `ArrayList`

  • `List`는 인터페이스(규칙)이고
  • `ArrayList`는 그 규칙을 실제로 구현한 클래스

3) `new Product()`

  • `new` = 메모리에 객체를 만든다
  • 생성자가 실행되면서 필드들이 세팅됨
  • 이때 상품 1개가 만들어짐

4) `List<Product> products = new Array List<>();`

왼쪽(`List`) -> USB-C 규격 / 기능 -> 이 변수는 List로 쓰겠다
오른쪽(`ArrayList`) -> 삼성 충전기 / 구현체 -> 이걸로 만들겠다!

- List는 여러 객체를 관리하기 위한 자료구조
- `List<타입>`을 사용하면 해당 타입만 담을 수 있음
- `new` 키워드는 객체를 메모리에 생성함

Array vs List 차이 정리

구분 Array List
크기 고정 유동
데이터 추가 불편 쉬움
삭제 불편 쉬움
실무 사용 제한적 매우 많음

👉 실무에서는 대부분 List 사용

 

 

3️⃣ 반복문으로 상품 목록 출력

1번부터 번호를 붙여서 각 상품의 name / price / descrption을 한 출로 출력
-> 리스트에 든 걸 하나씩 꺼내서 출력
// 상품명을 외부에서 읽을 수 있게 해 주는 getter
    public String getName() {
        return name;
    }

    // 가격을 외부에서 읽을 수 있게 해 주는 getter
    public int getPrice() {
        return price;
    }

    // 설명을 외부에서 읽을 수 있게 해 주는 getter
    public String getDescription() {
        return description;
    }

Product 클래스에 getter 추가

 

// 상품 목록 출력
        for (int i = 0; i < products.size(); i++) {

            // 리스트에서 i 번째 상품을 꺼낸다
            Product product = products.get(i);
            int menuNumber = i + 1;

            // 메뉴판 출력
            System.out.println(menuNumber + ". " + product.getName()
                    + " | " + product.getPrice() + "원"
                    + " | " + product.getDescription());
        }
        
        // 종료
        System.out.println("0. 종료        | 프로그램 종료");

main에 반복문 출력 추가

  • for문은 리스트 크기만큼 반복한다
  • `get(i)`로 i번째 요소를 꺼낸다
  • 사용자 메뉴 번호랑 인덱스는 다르다 그래서 `i + 1`이 필요하다

 

4️⃣ 입력을 받고 0이면 종료

1. 메뉴를 출력
2. 입력을 받고

3. 0이면 종료 메시지 출력 후 끝내야 되고?
4. 0 아니면 일단은 지원하지 않는다고 하고 다시 메뉴로......
package com.example.commerce;

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

public class Main {
    public static void main(String[] args) {

        // 사용자 입력을 받기 위한 Scanner
        Scanner sc = new Scanner(System.in);

        // 여러 Product를 담기 위한 List 생성
        List<Product> products = new ArrayList<>();

        // Product 객체 생성을 하고 List에 추가한다
        // new Produc()를 이용해서 실제 상품 객체를 생성한다
        products.add(new Product("Galaxy S25", 1200000, "최신 안드로이드 스마트폰", 50));
        products.add(new Product("iPhone 16", 1350000, "Apple의 최신 스마트폰", 30));
        products.add(new Product("MacBook Pro", 2400000, "M3 칩셋이 탑재된 노트북", 20));
        products.add(new Product("AirPods Pro", 350000, "노이즈 캔슬링 무선 이어폰", 100));

        // 프로그램을 계속 돌릴지 결정하는 변수
        boolean run = true;

        // run이 true인 동안 계속 반복
        while (run) {

            // 프로그램 시작 출력
            System.out.println("[ 실시간 커머스 플랫폼 - 전자제품]");

            // 상품 목록 출력
            for (int i = 0; i < products.size(); i++) {

                // 리스트에서 i 번째 상품을 꺼낸다
                Product product = products.get(i);
                int menuNumber = i + 1;

                // 메뉴판 출력
                System.out.println(menuNumber + ". " + product.getName()
                        + " | " + product.getPrice() + "원"
                        + " | " + product.getDescription());
            }

            // 종료
            System.out.println("0. 종료        | 프로그램 종료");

            // 입력 받음
            System.out.print("선택> ");
            int choice = sc.nextInt();

            // 입력 처리
            if (choice == 0) {
                System.out.println("커머스 플랫폼을 종료합니다");
                run = false;
            } else {
                System.out.println("아직 안 돼요 ㅜ");
            }

            System.out.println();

        }

        sc.close();

    }


}
package com.example.commerce;

// 상품 1개의 정보를 담는 클래스(설계도)
public class Product {
    
    // 필드 - 이 객체가 가지고 있어야 하는 정보를 저장하는 변수
    private String name;        // 상품명
    private int price;          // 가격
    private String description;  // 설명
    private int stock;          // 재고 수량


    // 생성자
    public Product(String name, int price, String description, int stock) {
        this.name = name;
        this.price = price;
        this.description = description;
        this.stock = stock;
    }

    // 상품명을 외부에서 읽을 수 있게 해 주는 getter
    public String getName() {
        return name;
    }

    // 가격을 외부에서 읽을 수 있게 해 주는 getter
    public int getPrice() {
        return price;
    }

    // 설명을 외부에서 읽을 수 있게 해 주는 getter
    public String getDescription() {
        return description;
    }

    // 재고를 외부에서 읽을 수 있게 해 주는 getter
    public int getStock() {
        return stock;
    }


}

 

  • `while`로 메뉴를 일단 반복 출력하게 만들었다
  • `choice == 0`일 때 `run = false`로 반복 종료하게 만들었다
  • `Scanner.nextInt()`로 입력을 받게 만듦

종료가 된다

 


🚩STEP 2 - 객체 지향 설계를 적용해 순서 제어를 클래스로 관리하기

- Main: 준비 담당(시작 버튼)
- CommerceSystem: 운영 담당(실제로 일하는 사람)
- products(List<Product>): 준비물(상품 목록)

Main이 준비물을 만들어서 CommerceSystem에게 주고, CommerceSystem은 그 준비물로 프로그램을 운영함
package com.example.commerce;


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

public class Main {
    public static void main(String[] args) {

        // 여러 Product를 담기 위한 List 생성
        List<Product> products = new ArrayList<>();

        // Product 객체 생성을 하고 List에 추가한다
        // new Produc()를 이용해서 실제 상품 객체를 생성한다
        products.add(new Product("Galaxy S25", 1200000, "최신 안드로이드 스마트폰", 50));
        products.add(new Product("iPhone 16", 1350000, "Apple의 최신 스마트폰", 30));
        products.add(new Product("MacBook Pro", 2400000, "M3 칩셋이 탑재된 노트북", 20));
        products.add(new Product("AirPods Pro", 350000, "노이즈 캔슬링 무선 이어폰", 100));

        // products를 CommerceSystem에 넘겨줌
        new CommerceSystem(products).start();

    }
}
package com.example.commerce;

import java.util.List;
import java.util.Scanner;

public class CommerceSystem {

    // Main에서 받은 상품 리스트를 저장할 필드
    private List<Product> products;

    // 생성자: Main이 만든 상품 리스트를 받음
    public CommerceSystem(List<Product> products) {
        this.products = products;
    }

    public void start() {

        // 사용자 입력을 받기 위한 Scanner
        Scanner sc = new Scanner(System.in);


        // 프로그램을 계속 돌릴지 결정하는 변수
        boolean run = true;

        // run이 true인 동안 계속 반복
        while (run) {

            // 프로그램 시작 출력
            System.out.println("[실시간 커머스 플랫폼 - 전자제품]");

            // 상품 목록 출력
            for (int i = 0; i < products.size(); i++) {

                // 리스트에서 i 번째 상품을 꺼낸다
                Product product = products.get(i);
                int menuNumber = i + 1;

                // 메뉴판 출력
                System.out.println(menuNumber + ". " + product.getName()
                        + " | " + product.getPrice() + "원"
                        + " | " + product.getDescription());
            }

            // 종료
            System.out.println("0. 종료        | 프로그램 종료");

            // 입력 받음
            System.out.print("선택> ");
            int choice = sc.nextInt();

            // 입력 처리
            if (choice == 0) {
                System.out.println("커머스 플랫폼을 종료합니다");
                run = false;
            } else {
                System.out.println("아직 안 돼요 ㅜ");
            }

            System.out.println();

        }

        sc.close();
    }
}
일단 Main에서 CommerceSystem.start()로 그대로 복사하고 start 함수를 만들어서 CommerceSystem 생성자를 통해 값을 할당하고 Main에 값을 넘겨 줌

 

 


🚩STEP 3 - 객체 지향 설계를 적용해 상품 카테고리와 고객 관리를 클래스 기반으로 관리하기

기본에 `Product`만 단순히 출력하던 구조를 Category / Customer 중심의 객체지향 구조로 확장하는 작업

1️⃣ `Category` 기반 구조로 변경

기존에는 `CommerceSysterm`이 `List<Product>`를 직접 관리하고 있었는데, 상품 관리는 Category가 담당하도록 구조를 변경했다

  • `Category` 클래스 = 카테고리 이름(name), 해당 카테고리에 속한 `List<Product>를 가진다
  • `CommerceSystem`은 더 이상 Product를 직접 관리하지 않고 `List<Category>`를 관리하면서 흐름 제어 역할만 담당한다

❗이 과정에서 `List<Category>`를 넘기는데 `List<Product>`를 받도록 되어 있어서 `incompatible types` 에러가 발생했고 step2 기준 지금 기준 구조에 맞게 수정하지 않아서 발생한 문제였다
👉 생성자 타입을 `List<Category>`로 수정하면서 해결

 

2️⃣ 카테고리 선택 -> 상품 목록 -> 상품 선택 구현

1. 메인 화면에서 카테고리 목록 출력
2. 카테고리 선택 시 해당 카테고리 진입
3. 카테고리 내부에서 상품 목록 출력
4. 상품 번호 선택 시 상품 상세 정보 출력
5. `0` 입력 시 뒤로가기 / 종료 처리

여기서 중첩 while문을 사용해서 메인 화면이랑 카테고리 화면을 전환하는 걸로 했다

 

3️⃣ Customer  객체를 통한 누적 주문 금액 & 등급 관리

상품 선택을 주문으로 한다 치면 `Customer` 객체를 추가해서 기능을 구현했다

  • 상품 선택 시 상품 가격을 고객의 누적 주문 금액에 추가
  • 누적 금액 기준으로 고객 등급 자동 변경

Customer는 본인의 상태를 관리하도록 하고 `addOrderAmount()` 메서드 내부에서 누적 금액 갱신과 등급 계산을 함께 처리했다

 


🚩STEP 4 - 캡슐화 적용하기

public List<Product> getProducts() {
        // 원본을 그대로 주지 않고, 원본을 복사한 "새 리스트"를 만들어서 준다
        return new ArrayList<>(products);
    }
`Category`의 products 리스트 원본을 그대로 반환하면, 외분에서 리스트를 마음대로 수정할 수 있어서 캡슐화가 깨진다. 그래서 getter는 원본이 아니라 복사본을 반환해 내부 상태를 보호한다.

 

public CommerceSystem(List<Category> categories, Customer customer) {

        // categories 원본을 그대로 들고 있지 않고 복사본 저장
        this.categories = new ArrayList<>(categories);

        // 필드 private
        this.customer = customer;
    }
생성자에서 리스트를 그대로 받으면 외부와 내부가 같은 리스트를 공유하게 되어 외부 수정이 내부 상태를 망가뜨릴 수 있다. 그래서 생성자에서 복사해서 저장해 객체 내부 상태를 보호한다.

 

// 상품 1개를 카테고리에 추가하는 메서드
    public void addProduct(Product product) {

        if (products == null) {
            return;
        }

        products.add(product); // 원본 리스트에 추가
    }

    // 상품 1개를 카테고리에서 삭제하는 메서드
    public void removeProduct(Product product) {

        // null이면 아무 것도 하지 않음
        if (products == null) {
            return;
        }

        products.remove(product);   // 원본 리스트에서 제거
    }
getProducts()로 원본을 주면 외부가 마음대로 수정해 캡슐화가 깨진다.
그래서 복사본을 주고, 실제 수정은 Category의 add/remove 같은 메서드로만 하게 만든다.

 

 

❗

// 생성자: Main이 만든 상품 리스트를 받음
    public CommerceSystem(List<Category> categories, Customer customer) {

        // categories 원본을 그대로 들고 있지 않고 복사본 저장
        this.categories = new ArrayList<>(categories);

        // customer가 null일 때 예외처리
        if (customer == null) {
            throw new IllegalArgumentException("Customer는 null일 수 없습니다.");
        }

        // 필드 private
        this.customer = customer;
    }
customer null이면 예외처리

 

❗

// 입력값이 숫자가 아닐 시에 예외처리
    private int readInt(Scanner sc, String message) {

        while (true) {

            // 안내 문구 출력
            System.out.println(message);

            String input = sc.nextLine();

            try {
                return Integer.parseInt(input);
            } catch (NumberFormatException e) {
                System.out.println("보기에 보이는 숫자만 입력해 주세요! ㅜㅜ");
            }

        }

    }
nextInt()는 다른 숫자를 누르거나 다른 입력을 하면 프로그램이 터진다...... 그래서 nextLine() + parseInt()로 입력을 받는 메서드를 만들어서 예외에도 반복 입력하도록 함

 

 


🚩도전기능 - Lv 1. 장바구니 및 주문하기 기능을 추가하기

🎯 전체 목표 정리

상품을 고르면 "장바구니에 담을래?" 물어보고, 담으면 장바구니에 저장해 두다가, 나중에 한 번에 주문하면서 재고를 줄이고 장바구니를 비운다.

1) CartItem (장바구니에 물건을 넣을 때는 상품 하나만 저장하는 것이 아니라 수량까지 넣는다)

  • `Product` (어떤 상품인가?)
  • `quantity` (몇 개 담았는가?)

2) Cart (CartItem들을 모아 놓는 곳)

  • `items` (List<CartItem>) - 얘도 캡슐화 진행해야 됨
  • `addItem` (product, quantity): 담기
  • `printCart()`: 장바구니 보여 주기
  • `getTotalPrice()`: 총금액 계산
  • `clear()`: 주문 확정 후 장바구니 비우기

 

1️⃣ 일단 출력하기

// 장바구니 추가 여부 질문
                        System.out.println();
                        System.out.println("\"" + selectedProduct.getName()
                                + " | " + formatPrice(selectedProduct.getPrice()) + "원"
                                + " | " + selectedProduct.getDescription()
                                + " | " + selectedProduct.getStock() + "\"");
                        System.out.println("위 상품을 장바구니에 추가하시겠습니까?");
                        System.out.println("1. 확인       2. 취소");

                        // 입력 받기
                        int addChoice = readInt(sc, "선택> ");

                        if (addChoice == 1) {
                            System.out.println("다음 단계: 수량 입력 및 장바구니 저장(음~ 아직 구현이 안 됐더요)");
                        } else if (addChoice == 2) {
                            System.out.println("장바구니 추가를 취소했습니다.");
                        } else {
                            System.out.println("잘못된 입력입니다.");
                        }

- 장바구니 추가할까요?
- 1이나 2 입력 받고  1이면 다음 단계로, 2면 그냥 카테고리 화면으로 계속

2️⃣ 장바구니 저장

package com.example.commerce;

public class CartItem {

    private Product product;
    private int quantity;

    // 상품과 수량 받아서 저장
    public CartItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }

    public Product getProduct() {
        return product;
    }

    public int getQuantity() {
        return quantity;
    }

    // 수량을 더해줌
    public void addQuantity(int quantity) {
        this.quantity += quantity;
    }
}
package com.example.commerce;

import java.util.ArrayList;

public class Cart {

    // 장바구니에 담긴 것들
    private ArrayList<CartItem> items = new ArrayList<>();

    // 장바구니에 상품 추가
    public void addItem(Product product, int quantity) {

        // 같은 상품이면 수량 더함
        for (CartItem item : items) {
            if (item.getProduct() == product) {
                item.addQuantity(quantity);
                return;
            }
        }

        items.add(new CartItem(product, quantity));
    }

    public boolean isEmpty() {
        return items.isEmpty();
    }

    public void printCart() {
        for (CartItem item : items) {
            Product product = item.getProduct();
            int quantity = item.getQuantity();

            System.out.println(product.getName() + " | " + product.getPrice() + "원"
                    + " | " + product.getDescription()
                    + " | 수량: " + quantity + "개 장바구니에 추가되었습니다." );
        }
    }

    public ArrayList<CartItem> getItems() {
        return new ArrayList<>(items);
    }

    public void clear() {
        items.clear();
    }

}
if (addChoice == 1) {

                            int quantity = readInt(sc, "수량: ");

                            // 수량이 1 이상인지 확인
                            if (quantity <= 0) {
                                System.out.println("수량은 1개 이상 입력하세요.");
                                continue;
                            }

                            // 재고 체크
                            if (quantity > selectedProduct.getStock()) {
                                System.out.println("재고가 부족합니다. 현재 재고: " + selectedProduct.getStock() + "개");
                                continue;
                            }

                            // 장바구니 추가
                            cart.addItem(selectedProduct, quantity);
                            System.out.println(selectedProduct.getName() + "가 " + quantity + "개 장바구니에 추가되었습니다.");

                        } else if (addChoice == 2) {
                            System.out.println("장바구니 추가를 취소했습니다.");
                        } else {
                            System.out.println("잘못된 입력입니다.");
                        }
상품 선택 -> 장바구니 확인(1) -> 수량 입력 ->  출력

 

3️⃣ 주문 관리

// 4번 장바구니 확인
            if (choice == 4) {
                if (cart.isEmpty()) {
                    System.out.println("장바구니가 비어있어용.");
                    continue;
                }

                System.out.println("[장바구니 내역]");
                
                for (CartItem item : cart.getItems()) {
                    
                    Product p = item.getProduct();
                    
                    int quantity = item.getQuantity();

                    System.out.println(p.getName() + " | " + formatPrice(p.getPrice()) + "원" 
                            + " | " + p.getDescription() + " | " + quantity + "개");
                }

                continue;
                
            }

            // 5번: 주문 취소 장바구니 비움
            if (choice == 5) {

                if (cart.isEmpty()) {
                    System.out.println("취소할 주문이 없습니다. 장바구니가 비어있습니다.");
                    continue;
                }

                cart.clear();

                System.out.println("진행중인 주문이 취소되었습니다. 장바구니를 비웠습니다.");
            }
장바구니에 상품이 있을 때만 주문 관리 메뉴를 보여 주고 입력값이 4나 5면 카테고리로 들어가 먼저 처리한 뒤 continue로 메인 메뉴로 돌아가게 했다.

 

4️⃣ 주문 확정 시에 재고 차감 및 장바구니 초기화

if (confirm == 1) {
                    totalPrice = 0;
                    for (CartItem item : cart.getItems()) {
                        Product p = item.getProduct();
                        int quantity = item.getQuantity();
                        totalPrice += p.getPrice() * quantity;

                        int beforeStock = p.getStock();
                        p.decreaseStock(quantity);
                        int afterStock = p.getStock();

                        System.out.println(p.getName() + " 재고가 " + beforeStock + "개에서 " + afterStock + "개로 업데이트되었습니다.");
                    }
                    customer.addOrderAmount(totalPrice);
                    cart.clear();
                    System.out.println("주문이 완료되었습니다...! 총 금액: " + String.format("%,d", totalPrice) + "원");
                } else if (confirm == 2) {
                    System.out.println("메인으로 돌아갑니다.");
                } else {
                    System.out.println("잘못된 입력입니다. 메인으로 돌아갑니다.");
                }

 

❗

customer.addOrderAmount(selectedProduct.getPrice());

테스트를 하는데 장바구니에 담는 순간 고객 금액 누적이 됐었다...... 삭제했다. 그리고

customer.addOrderAmount(totalPrice);

로 바꿔서 주문 완료할 때 바꾸는 걸로 했다

 

 


🚩도전기능 - Lv 2. 관리자 모드 추가

package com.example.commerce;

import java.util.List;
import java.util.Scanner;

public class AdminSystem {

    private final List<Category> categories;

    public AdminSystem(List<Category> categories) {
        this.categories = categories;
    }

    public void start(Scanner sc) {

        System.out.print("관리자 비밀번호를 입력하세요: ");
        String password = sc.nextLine();

        if (!"1234".equals(password)) {
            System.out.println("비밀번호가 틀렸습니다.");
            return;
        }

        System.out.println("관리자 모드에 진입");

    }

}

딱히 분리하라는 말은 없었지만 일단 너무 길어져서 분리했다

// 9번: 관리자 모드
            if (choice == 9) {

                adminSystem.start(sc);
                continue;
            }

이걸 추가해서 일단 밑의 결과처럼 나오게 했다

 

2번 수정하고 난 후......

 

더보기

와 이거 하는 거 진심 머리 터질 뻔했다 와...... 전혀 진도가 안 나가서 머리가 아팠다. 상품 삭제를 상품 번호로 입력해서 구현하려고 하다가 또 머리 아파서 수정이랑 비슷하게 검색으로 찾아서 하는 걸로 했다. 보통 이럴 때는 어떻게 해야 되지? 그리고 하나 하고 오류 나면 또 바꾸고 빨간 줄 왜 뜨나 고민하다가 막상 트러블 슈팅을 작성 제대로 못한 게 아쉽다.

AdminSystem으로 분리를 한 게 잘한 것 같다. 아 그리고 더 뭔가 분리할 수 있을 것 같은데...... 난 바보 감자 멍청이 쪼랩이지만 이래서 리팩토링을 하나 싶기도 하고 


🚩도전기능 - Lv 3. Enum, 람다 & 스트림을 활용한 고급 관리 기능

1️⃣ Enum을 활용한 고객 등급별 할인율 관리하기

Enum은 정해진 값만 쓸 수 있는 목록이다. Enum 안에 할인율 같은 정보도 같이 붙일 수 있다.
package com.example.commerce;

// 고객 등급
public enum CustomerGrade {

    BRONZE(0, "브론즈"),
    SLIVER(5, "실버"),
    GOLD(10, "골드"),
    PLATINUM(15, "플래티넘");

    private final  int discountPercentage;
    private final String description;

    CustomerGrade(int discountPercentage, String description) {
        this.discountPercentage = discountPercentage;
        this.description = description;
    }

    public int getDiscountPercentage() {
        return discountPercentage;
    }

    public String getDescription() {
        return description;
    }

    public long calculateDiscount(long amount) {
        return amount * discountPercentage / 100;
    }
}

주로 누적되는 금액은 21억을 넘길 수 있기 때문에 long으로 설정

 

2️⃣ 람다 & 스트림을 활용한 상품 검색 및 관리 기능

1) 람다(lambda) = 작은 규칙(기준)을 한 줄로 적는 방법

items.removeIf(item -> item.getProduct() == product);
  • `item` = 장바구니 한 칸(CartItem)
  • `->` = 그래서(그러면)
  • `item.getProduct() == product` = 이 조건이 맞으면 true
  • items 안에 있는 각 item을 보면서 item이 가진 product가 내가 지우려는 product랑 같으면 지워
  • 조건/동작을 짧게 적을 수 있고
  • 코드가 덜 길어짐

 

2) 스트림(stream) = 리스트를 컨베이어 벨트에 올림

  • for문으로 하나씩 꺼내서
  • 조건 검사하고
  • 출력하고
  • 합치고
  • 이 과정들을 컨베이어 벨트 위로 상품들이 지나가는데 필요한 것만 골라서(필터) 하고 싶은 일을 한다(출력/모으기)
  • `필터링 / 정렬 / 출력 / 합계` 같은 작업이 한 줄로 깔끔해짐
  • for문에서 if랑 continue가 섞이는 복잡함이 줄어든다

1. stream() = 컨베이어 벨트에 올린다

더보기
products.stream()

2. filter(...) = 조건에 맞는 것만 통과시킨다

더보기
.filter(p -> p.getPrice() <= 1000000)

3. forEach(...) / toList() = 마지막에 결과를 사용한다

  • 출력할 거면 `forEach()`
  • 새 리스트로 만들 거면 `toList()`
더보기
products.stream()
  .filter(p -> p.getPrice() <= 1000000)
  .forEach(p -> System.out.println(p.getName()));

product를 벨트에 올리고 100만원 이하만 통과시키고 통과한 애들 이름을 출력해라

 


🚩어려웠던 점과 느낀 점

더보기

솔직히 필수 기능까지 할 때는 할만하다고 생각했다. 도전기능 들어가고서는 맨날 머리를 싸매고 있었다. 생각보다 더 내가 개념을 제대로 알고 있는 게 아니구나..... 장바구니 기능을 구현할 때는 새로 만든 Cart와 CartItem 클래스를 어떻게 CommerceSystem에 적용해야 되는지부터 관리자 모드를 들어갔을 때는 CommerceSystem이 너무 길어져서 AdminSystem으로 분리를 하고 또 다시 적용을 하고 진짜 AI한테 힌트만 달라고 해서 적용하고 와중에 안 되면 정답도 알려 달라고 하면서 튜터님한테 가서도 물어보고 확인을 하고 정말 오래 걸렸다...... 와중에 스트림으로 넘어가니 스트림에서는 숫자를 잘못 쓴다거나 continue를 안 써서 무한 반복이 된다거나 이런 일들이 너무 많았다. 분명 위에 보면 차근차근 개념 정리를 하고 한다고 했는데 이러다 보니 시간이 훨씬 더 오래 걸린 것 같다. 막상 진짜로 어려운 도전 기능에 왔을 때는 시간에 쫓겨서 블로그를 신경 쓰지도 못했다. 오류가 났을 때 곧바로 캡처를 했어야 됐는데 그런 것도 생각이 안 났다. 

자바가 끝난 건가? 전혀 모르겠다...... 아직 개념이 안 잡힌 건 너무 많고 정확히 객체 지향이 어떤 건지도 솔직히 감이 안 온다. 코드가 너무 길어지는데? 쪼갤 수 있을 것 같은데? 내가 눈에 벌써 안 들어오는데? 이런 의문을 가지고 ProductFilter 이런 클래스로도 쪼개 봤다. 이런 생각들이 모이면 더 괜찮은 코드를 만들 수 있을까...... 사실 개념은 똑바로 잡힌 건지 의문이 든다. 이런 상태에서 Spring을 들어가도 되는 건가? 주말에는 좀 쉬어야 된다는 마인드였는데 자바를 조금 더 잘 공부해 보고 싶다...... 나는 너무 부족하다. 그래도 희망을 가질 수 있는 건? 좀 재미있다. 이거 분리해서 해 볼 수 있을 것 같은데?라는 생각이 든다는 게 재미있었다. 이제 한 지 거의 한 달이 다 되어 간다. 조금 더 노력을 해 보자. 이건 진짜로 리팩토링을 할 수 있을 것 같다..... 더 이쁘게 쪼갤 수 있었을 것 같다 계속 아쉽기만 하다 나중에 고쳐 봐야지


 

저작자표시 비영리 (새창열림)

'IL > WIL' 카테고리의 다른 글

[WIL] Spring - 일정 관리 앱 업글  (0) 2026.02.09
[WIL] Spring - 일정 관리 앱 만들기  (0) 2026.02.02
20260107 [WIL] 왜 Git을 배우는데 머리가 아플까  (0) 2026.01.07
'IL/WIL' 카테고리의 다른 글
  • [WIL] Spring - 일정 관리 앱 업글
  • [WIL] Spring - 일정 관리 앱 만들기
  • 20260107 [WIL] 왜 Git을 배우는데 머리가 아플까
견지
견지
개발로 개발하는지 새발로 개발하는지 내가 개인 건지 새인 건지 사람인 건지
  • 견지
    개발새발
    견지
  • 전체
    오늘
    어제
    • 분류 전체보기 (20)
      • ... (0)
      • IL (20)
        • TIL (16)
        • WIL (4)
        • MIL (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    java
    JavaScript
    DB
    HTML
    git
    CSS
    JSP
    oracle
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
견지
[WIL] - Java 커머스 과제
상단으로

티스토리툴바