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로 판매 데이터 내보내기
┌──────────────────────────────────────────────────────────┐
│ 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 # 오류 메시지 표시
// App.java
MainView mainView = new MainView(purchaseController, products, cart);
purchaseController.setMainView(mainView); // 생성 후 setter로 주입MainView와 PurchaseController가 서로를 참조하는 구조에서
생성자 주입 대신 setter 주입을 사용해 순환 참조 문제를 해결했습니다.
// Product.java
public synchronized boolean reduceStock(int qty) {
if (stock < qty) return false;
stock -= qty;
return true;
}동시에 여러 스레드가 재고를 차감하는 상황을 synchronized 키워드로 방지해
재고가 음수가 되는 Race Condition을 차단했습니다.
// Cart.java
public Map<Product, Integer> getItems() {
return new HashMap<>(items); // 내부 데이터 직접 노출 방지
}내부 HashMap을 직접 반환하지 않고 복사본을 반환해
외부에서 장바구니 데이터를 임의로 수정하지 못하도록 했습니다.
// ViewInterface.java
public interface ViewInterface {
void refresh();
void showMessage(String message);
void showAlert(String message);
}MainView와 PurchaseView 모두 ViewInterface를 구현해
Controller가 구체적인 View 클래스를 몰라도 동일한 방식으로 화면을 갱신할 수 있습니다.
// PurchaseController.java
PurchaseView purchaseView = new PurchaseView(mainView, cart);
purchaseView.setVisible(true); // 창이 닫힐 때까지 여기서 대기
if (purchaseView.isConfirmed()) { // 닫힌 후 결과 확인
processPurchase();
}modal=true JDialog의 특성을 활용해 비동기 콜백 없이
사용자의 결제 확인 여부를 동기적으로 처리했습니다.
// 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개 카테고리
| 원칙 | 적용 위치 |
|---|---|
| 캡슐화 | Product — private final 필드 + synchronized getter, Cart — 방어적 복사 |
| 상속 | MainView extends JFrame, PurchaseView extends JDialog |
| 다형성 | ViewInterface — MainView, PurchaseView를 공통 타입으로 처리 |
| 인터페이스 | ViewInterface (refresh / showMessage / showAlert 계약 정의) |
| 의존성 주입 | App.java에서 생성자 주입 + setter 주입으로 결합도 최소화 |
| 단일 책임 | Model(데이터 관리), View(화면 표시), Controller(흐름 제어) 각자 하나의 책임 |
OOP(객체지향 프로그래밍) 수업 팀 프로젝트 · 2026-1