공공부하자개발 · 영어 학습 노트
자바
미니 프로젝트쇼핑몰 정산 시스템 4단계0/4 완료
  • 011단계: 콘솔 주문 관리 (초급 기술)
  • 022단계: 객체지향 리팩터링 (중급 기술)
  • 033단계: 모던 자바 적용 (고급 기술)
  • 044단계: 일마감 정산 배치 (배치 기술)
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 미니 프로젝트 › 01 / 4

1단계: 콘솔 주문 관리 (초급 기술)

섹션 6진행 0 / 4
1이번 단계의 목표2설계3구현 따라가기4실행 결과와 해설5확장 과제6다음 단계로‹ 이전다음 ›

5. 확장 과제

과제 1: 주문 취소와 재고 복구

cancelOrder(int orderId)를 추가하라. 해당 주문의 항목마다 재고를 되돌리고, orders 배열에서 그 주문을 제거한 뒤 뒤쪽 원소를 한 칸씩 앞으로 당겨 빈틈을 없애야 한다. 없는 주문이면 [실패] 존재하지 않는 주문: N을 출력한다. Product에 increaseStock(int)를 추가해야 한다.

정답 보기
java
// Product.java에 추가
public void increaseStock(int qty) { stock += qty; }

// Main.java에 추가
static void cancelOrder(int orderId) {
    int index = -1;
    for (int i = 0; i < orderCount; i++) {
        if (orders[i].getId() == orderId) { index = i; break; }
    }
    if (index < 0) {
        System.out.println("[실패] 존재하지 않는 주문: " + orderId);
        return;
    }
    Order o = orders[index];
    for (int j = 0; j < o.getLineCount(); j++) {
        findProduct(o.getProductId(j)).increaseStock(o.getQuantity(j));   // 재고 복구
    }
    for (int i = index; i < orderCount - 1; i++) {
        orders[i] = orders[i + 1];                       // 한 칸씩 앞으로 (ArrayList.remove가 하는 일)
    }
    orders[orderCount - 1] = null;                       // 마지막 칸 비우기
    orderCount--;
    System.out.println("주문 취소: #" + orderId);
}

ArrayList.remove(index)가 내부에서 System.arraycopy로 하는 일을 손으로 쓴 것이다. 원소를 당기는 루프가 O(n)인 이유가 코드에 보인다.

과제 2: 배열 자동 확장

MAX_ORDERS를 없애고, 주문 배열이 가득 차면 1.5배 크기의 새 배열을 만들어 기존 내용을 복사한 뒤 계속 저장하도록 createOrder를 고쳐라. java.util.Arrays.copyOf를 써도 되고 직접 루프를 돌려도 된다. 확장이 일어날 때 배열 확장: 3 → 4처럼 로그를 남겨라.

정답 보기
java
// 정답: 확장 전용 메서드
static void ensureOrderCapacity() {
    if (orderCount < orders.length) return;
    int newCapacity = orders.length + (orders.length >> 1);   // 1.5배 (ArrayList와 같은 정책)
    if (newCapacity == orders.length) newCapacity++;          // 길이 1일 때 방어
    Order[] bigger = new Order[newCapacity];
    for (int i = 0; i < orderCount; i++) bigger[i] = orders[i];
    System.out.println("배열 확장: " + orders.length + " → " + newCapacity);
    orders = bigger;
}

// createOrder에서 "주문 저장 공간이 가득 찼습니다" 검사 대신:
//   ensureOrderCapacity();
//   ... (검증) ...
//   orders[orderCount] = order;

orders는 static Order[]이므로 final이 아니어야 재할당할 수 있다. 이 12줄이 ArrayList.add의 핵심이고, 2단계에서는 이 코드를 통째로 new ArrayList<>()로 바꾼다.

과제 3: 카테고리별 매출

printSalesByCategory()를 추가하라. 상품의 카테고리별로 매출 합계를 출력해야 한다. 컬렉션 없이 하려면 "지금까지 본 카테고리 이름"을 String[]에, 합계를 같은 인덱스의 int[]에 모으는 병렬 배열이 필요하다. 카테고리는 최대 10개로 가정한다. 출력 순서는 처음 등장한 순서.

정답 보기
java
// 정답
static void printSalesByCategory() {
    String[] names = new String[10];
    int[] sums = new int[10];
    int count = 0;

    for (int i = 0; i < orderCount; i++) {
        Order o = orders[i];
        for (int j = 0; j < o.getLineCount(); j++) {
            Product p = findProduct(o.getProductId(j));
            int amount = p.getPrice() * o.getQuantity(j);

            int idx = -1;                                   // 카테고리 위치 찾기 (선형 탐색)
            for (int k = 0; k < count; k++) {
                if (names[k].equals(p.getCategory())) { idx = k; break; }
            }
            if (idx < 0) {                                  // 처음 보는 카테고리
                names[count] = p.getCategory();
                idx = count;
                count++;
            }
            sums[idx] += amount;
        }
    }
    for (int k = 0; k < count; k++) {
        System.out.println("카테고리별 매출: " + names[k] + " " + format(sums[k]) + "원");
    }
}
// 출력 (3.7의 데이터 기준):
// 카테고리별 매출: 전자 83,000원
// 카테고리별 매출: 도서 32,000원
// 카테고리별 매출: 생활 45,000원

"이름 배열에서 위치를 찾고, 없으면 끝에 추가하고, 그 위치의 합계에 더한다" — 이것이 Map.merge(category, amount, Integer::sum) 한 줄이 하는 일이다. 2단계에서 직접 비교해 본다.

확장 과제
  • 과제 1: 주문 취소와 재고 복구
  • 과제 2: 배열 자동 확장
  • 과제 3: 카테고리별 매출
이전 섹션4 실행 결과와 해설5 / 6다음 섹션6 다음 단계로