Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 

Repository files navigation

🏪 스마트 자판기

Java 기반 스마트 자판기 프로그램입니다.


📌 프로젝트 개요

Java와 Swing을 활용해 실제 자판기의 구매·결제·관리 흐름을 소프트웨어로 구현한 팀 프로젝트입니다.
MVC(Model-View-Controller) 아키텍처를 기반으로 역할을 명확히 분리하고,
OOP 원칙(캡슐화·다형성·인터페이스)을 적용해 유지보수 가능한 구조로 설계했습니다.


👥 팀 구성 및 역할

이름 담당 파트
정지윤 사용자 구매 흐름 (Product, Cart, PurchaseController, MainView, PurchaseView, ViewInterface)
현진서 결제 및 오류 처리 (PaymentController, Payment, Transaction, PaymentView, ErrorMessageView, 예외처리)
정유진 관리자 시스템 (AdminController, InventoryManager, SalesManager, SalesRecord, AdminView, SalesRecordView)

🛠 기술 스택

분류 기술
Language Java 17
UI Framework Java Swing (JFrame, JDialog, JPanel)
Architecture MVC Pattern
Build javac
IDE VS Code / IntelliJ IDEA / Eclipse

✨ 주요 기능

👤 사용자 — 구매 흐름

  • 카테고리 탭 전환 — 음료 / 간식 / 생활용품 카테고리별 상품 표시
  • 장바구니 담기 / 빼기 — 상품 카드에서 수량 조절 및 재고 초과 방어 처리
  • 결제 확인 팝업 — 주문 내역과 합계 확인 후 결제 진행 여부 선택 (modal JDialog)
  • 전체 취소 — 장바구니 초기화 전 확인 다이얼로그 표시

💳 결제 시스템

  • 금액 투입 및 검증 — 투입 금액 부족 시 InsufficientBalanceException 발생
  • 재고 재검증 — 결제 시점에 재고 재확인 후 OutOfStockException 발생
  • 거스름돈 계산 및 영수증 출력 — UUID 기반 거래번호 포함 영수증 표시
  • 오류 복구 — 예외 발생 시 투입 금액 자동 환불 처리

🔧 관리자 시스템

  • 전체 재고 조회 — 전체 상품 목록 및 재고 현황 표시
  • 품절 / 재고 부족 상품 조회 — 재고 0개(품절) / 2개 이하(부족) 상품 필터링
  • 재고 보충 — 상품명 입력으로 재고 수량 보충
  • 판매 기록 조회 — 결제 완료된 상품의 판매 이력 확인
  • 판매 기록 파일 저장sales_record.txt로 판매 데이터 내보내기

🏗 아키텍처

MVC 패턴 구조

┌──────────────────────────────────────────────────────────┐
│                        App.java                          │
│             (객체 생성 및 의존성 주입 진입점)               │
└───────────────────────┬──────────────────────────────────┘
                        │ 생성 & 연결
          ┌─────────────┼──────────────┐
          ▼             ▼              ▼
     [Controller]    [Model]        [View]
  PurchaseController  Product       MainView
  PaymentController   Cart          PurchaseView
  AdminController     Payment       AdminView
                      InventoryMgr  PaymentView
                      SalesManager  SalesRecordView

패키지 구조

src/
├── App.java                           # 진입점 (DI 컨테이너 역할)
├── controller/
│   ├── PurchaseController.java        # 구매 흐름 제어
│   ├── PaymentController.java         # 결제 처리 제어
│   └── AdminController.java           # 관리자 기능 제어
├── model/
│   ├── Product.java                   # 상품 (재고 동기화)
│   ├── Cart.java                      # 장바구니 (HashMap 기반)
│   ├── Payment.java                   # 결제 금액 모델
│   ├── Transaction.java               # 거래 영수증 데이터
│   ├── InventoryManager.java          # 재고 관리
│   ├── SalesManager.java              # 판매 기록 관리
│   ├── SalesRecord.java               # 판매 기록 단건
│   ├── InsufficientBalanceException   # 잔액 부족 커스텀 예외
│   └── OutOfStockException            # 품절 커스텀 예외
└── view/
    ├── ViewInterface.java             # View 공통 인터페이스
    ├── MainView.java                  # 메인 화면 (JFrame)
    ├── PurchaseView.java              # 결제 확인 팝업 (JDialog)
    ├── AdminView.java                 # 관리자 화면 (JFrame)
    ├── PaymentView.java               # 결제 입력 화면
    ├── SalesRecordView.java           # 판매 기록 조회 화면
    └── ErrorMessageView.java          # 오류 메시지 표시

💡 핵심 설계 포인트

1. 순환 참조 방지 — Setter Injection

// App.java
MainView mainView = new MainView(purchaseController, products, cart);
purchaseController.setMainView(mainView);  // 생성 후 setter로 주입

MainViewPurchaseController가 서로를 참조하는 구조에서
생성자 주입 대신 setter 주입을 사용해 순환 참조 문제를 해결했습니다.


2. 스레드 안전 재고 관리 — synchronized

// Product.java
public synchronized boolean reduceStock(int qty) {
    if (stock < qty) return false;
    stock -= qty;
    return true;
}

동시에 여러 스레드가 재고를 차감하는 상황을 synchronized 키워드로 방지해
재고가 음수가 되는 Race Condition을 차단했습니다.


3. 캡슐화 — 방어적 복사

// Cart.java
public Map<Product, Integer> getItems() {
    return new HashMap<>(items);  // 내부 데이터 직접 노출 방지
}

내부 HashMap을 직접 반환하지 않고 복사본을 반환해
외부에서 장바구니 데이터를 임의로 수정하지 못하도록 했습니다.


4. 다형성 — ViewInterface

// ViewInterface.java
public interface ViewInterface {
    void refresh();
    void showMessage(String message);
    void showAlert(String message);
}

MainViewPurchaseView 모두 ViewInterface를 구현해
Controller가 구체적인 View 클래스를 몰라도 동일한 방식으로 화면을 갱신할 수 있습니다.


5. modal JDialog — 동기적 사용자 확인

// PurchaseController.java
PurchaseView purchaseView = new PurchaseView(mainView, cart);
purchaseView.setVisible(true);         // 창이 닫힐 때까지 여기서 대기
if (purchaseView.isConfirmed()) {      // 닫힌 후 결과 확인
    processPurchase();
}

modal=true JDialog의 특성을 활용해 비동기 콜백 없이
사용자의 결제 확인 여부를 동기적으로 처리했습니다.


6. 커스텀 예외로 결제 오류 분리

// PaymentController.java
payment.checkBalance();                      // → InsufficientBalanceException
if (entry.getKey().getStock() < qty)
    throw new OutOfStockException(...);      // → OutOfStockException

잔액 부족과 품절이라는 두 가지 결제 실패 상황을 커스텀 예외 클래스로 분리해
catch 블록에서 오류 유형별 처리가 명확하게 이루어집니다.


🖥 실행 방법

요구 사항

  • Java 17 이상

컴파일 및 실행

# 프로젝트 루트에서 컴파일
javac -d bin -sourcepath src src/App.java

# 실행
java -cp bin App

📦 상품 구성 (초기 데이터)

카테고리 상품 가격 범위 초기 재고
음료 콜라, 커피, 생수, 녹차, 과일주스, 비타민음료 1,000 ~ 1,800원 3 ~ 8개
간식 초코바, 덴탈껌, 젤리, 쿠키, 사탕, 프레첼 500 ~ 1,200원 3 ~ 8개
생활용품 마스크, 핫팩, 손소독제, 반창고, 가글, 휴대용 티슈 800 ~ 2,500원 3 ~ 10개

18개 상품, 3개 카테고리


📐 적용된 OOP 원칙

원칙 적용 위치
캡슐화 Productprivate final 필드 + synchronized getter, Cart — 방어적 복사
상속 MainView extends JFrame, PurchaseView extends JDialog
다형성 ViewInterfaceMainView, PurchaseView를 공통 타입으로 처리
인터페이스 ViewInterface (refresh / showMessage / showAlert 계약 정의)
의존성 주입 App.java에서 생성자 주입 + setter 주입으로 결합도 최소화
단일 책임 Model(데이터 관리), View(화면 표시), Controller(흐름 제어) 각자 하나의 책임


OOP(객체지향 프로그래밍) 수업 팀 프로젝트 · 2026-1

About

Java 기반 스마트 자판기 프로젝트 레포지토리입니다.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages