JAVA/Study

[JAVA] 자판기 만들기 실습

웹코린이 2023. 6. 3. 15:20
728x90

오늘은 하나의 클래스 안에서 자판기를 구현하는 방법을 공부해보려고 한다.

 

[ 설계서 ]

- Product 클래스 [ VO, DAO 역할 ]

우선 만들 자판기의 기능을 크게 두가지로 나누면

  • 사용자 모드
  • 관리자 모드

위와 같이 두가지의 기능으로 분류하고 사용자 모드에는

  • 상품 목록 출력
  • 상품 구매

두개의 기능을 구현할 예정이고, 관리자 모드에서는

  • 상품 추가
  • 상품 재고 변경
  • 상품 삭제

이렇게 3가지 기능을 구현할 예정이다.

 

멤버 변수로는

  • 상품 PK
  • 이름
  • 가격
  • 재고량

을 선언할 예정이고, 외부 class에서 접근할 수 없도록 private로 선언한다. 또한 외부 클래스에서 사용하기 위해서 getter, setter도 같이 생성할 예정이다. 

 

생성자로는 멤버변수 4가지를 모두 main()에서 입력받을 것이기 때문에, 매개 변수로 생성할 예정이다.

 

기능을 구현할 메소드로는 

  • sell() [ 판매 출력 및 현재 재고량 - 사용자의 입력값을 연산하기 위한 메소드 (매개변수로는 사용자의 입력값인 count 입력 값을 넣을 예정 ]
  • changeProduct() [ 재고 변경 메소드, 현재 재고량 + 사용자의 입력값을 연산하기 위한 메소드 (매개변수로는 사용자의 입력값인 productStock을 넣을 예정 ]
  • toString() 재정의(오버라이딩) [상품 목록 출력시 재고량이 0일 경우 품절, 그게 아니라면 현재 재고량을 보여주기 위한 재정의 ]

 

- main()

먼저, 상품이 어떤것이 얼만큼 생성될지 모르기 때문에 배열리스트인 ArrayList를 사용할 예정

[ ArrayList<Product> data = new ArrayList<Product>(); ]

 

상품은 모두 고유한 상품번호를 가지고 있기 때문에 PK를 설정해 줄 예정

[  int numPK = 1 ] --> 상품의 번호는 1부터 시작

 

사용자의 입력 값을 저장하기 위한 변수 action을 선언 -> 사용자의 입력값에 따른 로직으로 구성할 예정

[ int action ]

 

프로그램은 종료 버튼을 누르기 전까지 종료하지 않을 예정이므로, while(true)를 통해 무한루프를 돌릴 예정

그에 따른 종료 조건은 제일 밑의 메뉴인 '3'번에 '프로그램 종료' 버튼을 만들 예정

 

사용자 모드

  • 사용자의 입력값이 '1' 일 경우 [ 상품 목록 출력 ]
  • 사용자의 입력값이 '2'일 경우 [ 상품 구매 ]
  • 사용자의 입력값이 '3'일 경우 [ 프로그램 종료 ]

관리자 모드 [ 사용자모드에서 사용자의 입력값이 '1234'일 경우로 설정 ]

  • 관리자의 입력값이 '1'일 경우 [ 상품 추가 ]
  • 관리자의 입력값이 '2'일 경우 [ 상품 재고 변경 ]
  • 관리자의 입력값이 '3'일 경우 [ 상품 삭제 ]
  • 관리자의 입력값이 '4'일 경우 [ 관리자 모드 종료 및 사용자 모드 활성화 ]

[ 코드 구현 ]

Product 클래스

class Product {
	private int productNum; // PK
	private String productName; // 상품 이름
	private int productPrice; // 상품 가격
	private int productStock; // 상품 재고

// 생성자 ===========================================================================================

	Product(int productNum, String productName, int productPrice, int productStock) { // 4가지 모두 입력받을 예정
		this.productNum = productNum;
		this.productName = productName;
		this.productPrice = productPrice;
		this.productStock = productStock;
	}
    
// 구현 메소드 ===========================================================================================
    
    // [상품 구매]
	void sell(int count) { 
		System.out.println(this.productName + "상품은 " + count + "개 구매 완료 !");
		this.productStock -= count; // 재고에서 구매한 만큼의 개수 빼기
	}

    // [ 재고 변경]
	void changeProduct(int productStock) {
		System.out.print(this.productName + "상품은 " + this.productStock + "개에서 "); // 이전 재고 개수
		this.productStock += productStock; // 재고 개수가 추가된 만큼 더해줌
		System.out.println(this.productStock + " 으로 변경되었습니다."); // 변경된 재고 개수
	}

// toString() 재정의 ===========================================================================================
	
    @Override
	public String toString() { // toString 재정의하여 상품 목록 출력 메뉴 사용 시 출력
		if (this.productStock == 0) { // 재고가 0개라면
			return this.productNum + ". " + this.productName + " : " + this.productPrice + "[품절]"; // 품절 출력
		}
		return this.productNum + ". " + this.productName + " : " + this.productPrice + "[" + this.productStock + "]";
	}
    
// getter & setter ===========================================================================================
	
    public int getProductNum() {
		return productNum;
	}

	public void setProductNum(int productNum) {
		this.productNum = productNum;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public int getProductPrice() {
		return productPrice;
	}

	public void setProductPrice(int productPrice) {
		this.productPrice = productPrice;
	}

	public int getProductStock() {
		return productStock;
	}

	public void setProductStock(int productStock) {
		this.productStock = productStock;
	}
}

 

main()

선언부

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

		Scanner sc = new Scanner(System.in); 
		ArrayList<Product> data = new ArrayList<Product>(); // Product 클래스 객체 생성

		int numPk = 1; // 상품의 번호는 1부터 시작
		int action; // 사용자의 메뉴 번호 입력값을 저장할 변수

위의 설계서와 같이 리스트배열과 PK, action 변수 선언과 입력을 하기 위한 Scanner 함수 생성

 

구현부

사용자 메뉴 출력 및 무한 반복문 ( + 종료 조건 )

		// 첫 화면
		System.out.println("==============");
		System.out.println("1. 상품 목록 출력");
		System.out.println("2. 구매하기");
		System.out.println("3. 프로그램 종료");
		System.out.println("==============");
		System.out.println();
		System.out.print("사용할 메뉴를 선택하세요. ");
		action = sc.nextInt(); // 사용자의 입력
		while (true) { // 프로그램이 종료되지 않도록 무한 반복
			if (action == 3) { // 3. 프로그램종료
				System.out.println("프로그램을 종료합니다.");
				System.out.println();
				break;
			}

 

처음 코드 : 사용자 모드 메뉴 1번 ( 상품 목록 출력 ) + 처음 toString() 재정의

    	@Override
		public String toString() { // toString 재정의하여 상품 목록 출력 메뉴 사용 시 출력
			return this.productNum + ". " + this.productName + " : " + this.productPrice + "[" + this.productStock + "]";
		}

		...

		else if (action == 1) { // 1. 상품목록출력 (재고없는상품은 [품절])
			System.out.println("=== 상품 목록 ===");
			for (Product product : data) { // ArrayList에 저장된 값들을 출력하기 위해 forEach문 사용
				System.out.println(product); // 저장된 값들 출력
			}
			System.out.println("상품 출력 완료 ! 메뉴로 돌아갑니다.");
			System.out.println();
		}

위와 같이 재정의 후 출력을 할 경우에 재고가 0인 경우 [품절] 로 뜨지 않고, 0으로 뜨는 것을 알게 되었고 아래와 같이 수정해 보았다.

 

수정 [toString() if문 추가]

    	@Override
		public String toString() { // toString 재정의하여 상품 목록 출력 메뉴 사용 시 출력
        	// 수정 부분 [if 조건문]
            if(this.productStock == 0) {
            	return this.productNum + ". " + this.productName + " : " + this.productPrice + "[ 품절 ]";
            }
			return this.productNum + ". " + this.productName + " : " + this.productPrice + "[" + this.productStock + "]";
		}

		...

		else if (action == 1) { // 1. 상품목록출력 (재고없는상품은 [품절])
			System.out.println("=== 상품 목록 ===");
			for (Product product : data) { // ArrayList에 저장된 값들을 출력하기 위해 forEach문 사용
				System.out.println(product); // 저장된 값들 출력
			}
			System.out.println("상품 출력 완료 ! 메뉴로 돌아갑니다.");
			System.out.println();
		}

 

2. 상품 구매

class Product {

	...
	// [ 상품 구매 메소드]
	void sell(int count) { 
		System.out.println(this.productName + "상품은 " + count + "개 구매 완료 !");
		this.productStock -= count; // 재고에서 구매한 만큼의 개수 빼기
	}

	...

}

...

	else if (action == 2) { // 2. 구매하기
		System.out.println("=== 상품 목록 ===");
		for (Product product : data) { // 사용자가 구매를 눌렀을 시 메뉴를 보기 편하도록 상품 목록 출력
			System.out.println(product);
		}
		int cnt = 0; // 구매할 개수 0으로 초기화
			while (true) {
				System.out.println();
				System.out.print("구매할 상품의 번호를 입력하세요. ");
				int num = sc.nextInt();
                
				System.out.println(data.get(i)); // 사용자가 입력한 상품
				System.out.println("위 상품을 구매하시겠습니까 ? ");
				System.out.println("1. Yes     2. No ");
				System.out.print("번호 입력) ");
				int isTrue = sc.nextInt();

				if (isTrue == 1) { // 상품을 구매하겠다면
				System.out.print("상품의 개수를 구매하실 만큼 입력하세요. ");
				cnt = sc.nextInt();

				int total = data.get(i).getProductPrice() * cnt; // 총 가격 연산
				System.out.println("상품의 개수는 " + cnt + "개이고, 가격은 " + total + "원 입니다.");
				System.out.println("1. 구매하기      2. 구매하지 않기 ");
				System.out.print("번호 입력) ");
				int isBuy = sc.nextInt();
				if (isBuy == 1) {
					data.get(i).sell(cnt); // Product 클래스의 sell() 메소드 사용
					break; // 이중 반복문 즉시 종료
				} else if (isBuy == 2) {
					System.out.println("구매하지 않아 메뉴로 돌아갑니다. ");
					break; // 메뉴로 이동
				}
			} else if (isTrue == 2) {
				System.out.println("구매하지 않아 메뉴로 돌아갑니다. ");
				break;
			}
		}
	}	
}

상품 구매의 경우 사용자가 구매하려는 상품의 개수만큼 기존의 상품 재고량에서 빼주는 기능을 하는 메소드를 Product 클래스에서 따로 구현 및 출력을 하도록 설정해놓았다. 

 

관리자 모드 진입 및 메뉴 ( + 종료 조건)

} else if (action == 1234) { // 관리자 모드 접근
	while (true) { // 관리자 모드 진입
		String name; // 입력 받을 이름 변수
		int price; // 입력 받을 가격 변수
		int stock; // 입력 받을 재고 변수

		System.out.println("관리자 프로그램을 실행합니다.");
		System.out.println();
		System.out.println("=== 관리자 프로그램 ===");
		System.out.println("1. 상품 추가");
		System.out.println("2. 상품 재고 변경");
		System.out.println("3. 상품 삭제");
		System.out.println("4. 관리자 프로그램 종료");
		System.out.println();
		System.out.print("사용할 메뉴를 선택해주세요. ");
		int action2 = sc.nextInt();
        
        if (action2 == 4) { // 4. 관리자모드종료
			System.out.println("사용자 프로그램으로 돌아갑니다.");
			break;
		}

	...

관리자 모드 진입 방법을 사용자 메뉴의 입력 부분에서 1234를 입력 시 접근할 수 있도록 설정해놓았다. 또한, 무한 반복을 설정해 놓았으므로 종료조건( 사용자의 입력값이 '4' 일 경우 )도 같이 설정해놓은 것을 볼 수 있다.

 

3. 상품 추가

else if (action2 == 1) { // 1. 상품추가
		System.out.print("추가할 상품의 이름을 입력하세요. ");
		name = sc.next();
		System.out.println(name + "으로 사용하시겠습니까 ? ");
		System.out.print("1. Yes      2. No ");

		System.out.print("상품의 가격을 입력하세요. ");
		price = sc.nextInt();

		System.out.print("상품의 재고를 입력하세요. ");
		stock = sc.nextInt();

		System.out.println(numPk + ". " + name + " " + price + "원 " + stock + "개 생성완료!"); // 가독성을 위해 출력
		data.add(new Product(numPk++, name, price, stock)); // 입력받은 값 저장
}

사용자가 상품 추가를 눌렀다면, 추가할 상품의 이름, 가격, 재고량을 입력 받고 그것을 ArrayList<Product> data에 저장하는 기능을 구현해놓았다.

 

4. 상품 재고 변경

class Product {
	...
    
     // [ 재고 변경]
	void changeProduct(int productStock) {
		System.out.print(this.productName + "상품은 " + this.productStock + "개에서 "); // 이전 재고 개수
		this.productStock += productStock; // 재고 개수가 추가된 만큼 더해줌
		System.out.println(this.productStock + " 으로 변경되었습니다."); // 변경된 재고 개수
	}

	...
}


else if (action2 == 2) { // 2. 상품재고변경

	System.out.println("=== 상품 목록 ===");
	for (Product product : data) { // ArrayList에 저장된 값들을 출력하기 위해 forEach문 사용
		System.out.println(product); // 저장된 값들 출력
	}
	System.out.println();
	System.out.print("변경할 상품의 번호를 입력해주세요. ");
	int num = sc.nextInt();

	int i = 0;
	while (i < data.size()) { // 지금까지 입력받은 값들이 있는 배열 리스트 안에
		if (num == data.get(i).getProductNum()) { // 입력한 번호와 맞는 내 번호가 있니 ?
			System.out.println(data.get(i).getProductName() + "상품의 재고를 변경합니다. "); // 입력할 번호에 있는
			System.out.print("변경할 상품의 재고를 추가할만큼 입력해주세요. ");
			stock = sc.nextInt();

			data.get(i).changeProduct(stock); // 입력한 번호의 상품을 changeProduct()로 실행한다.
			break;
		}
	}
}

상품 재고 변경을 입력하였다면, 상품의 번호를 사용자에게 입력받아 상품의 재고의 PK를 기존의 데이터에서 찾아 추가할 만큼 입력을 받고 위에 선언해 놓은 메소드를 호출하여 현재 재고량 + 사용자의 입력값을 하도록 구현해 놓았다. 또한 사용자의 편의성을 위해 출력문을 설정해놓았다.

 

5. 상품 삭제

 else if (action2 == 3) { // 3. 상품삭제
	int num;
	System.out.print("삭제할 상품의 번호를 입력해주세요. ");
	num = sc.nextInt();

	for (int i = 0; i < data.size(); i++) { // 지금까지 입력받은 값들이 있는 배열 리스트 안에
		if (num == data.get(i).getProductNum()) { // 혹시 지금 입력받은 번호가 배열 리스트에 있니 ?
			System.out.println(data.get(i).getProductName() + "상품 삭제 완료! ");
			data.remove(i); // 그번호의 상품 삭제하기
			break;
		}
	}
}

상품 삭제를 입력하였다면, 삭제할 상품의 PK를 입력 받아 기존의 데이터를 통해 찾은 후 그 상품을 삭제하도록 설정하였다.

 

최종 코드

package test;

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

// 상품 : PK,이름,가격,재고
//   판매()
//   재고변경()
// 관리자 모드 Password : 1234

class Product {
	private int productNum; // PK
	private String productName; // 상품 이름
	private int productPrice; // 상품 가격
	private int productStock; // 상품 재고

	Product(int productNum, String productName, int productPrice, int productStock) { // 4가지 모두 입력받을 예정
		this.productNum = productNum;
		this.productName = productName;
		this.productPrice = productPrice;
		this.productStock = productStock;
	}

	void sell(int count) {
		System.out.println(this.productName + "상품은 " + count + "개 구매 완료 !");
		this.productStock -= count; // 재고에서 구매한 만큼의 개수 빼기
	}

	void changeProduct(int productStock) {
		System.out.print(this.productName + "상품은 " + this.productStock + "개에서 "); // 이전 재고 개수
		this.productStock += productStock; // 재고 개수가 추가된 만큼 더해줌
		System.out.println(this.productStock + " 으로 변경되었습니다."); // 변경된 재고 개수
	}

	@Override
	public String toString() { // toString 재정의하여 상품 목록 출력 메뉴 사용 시 출력
		if (this.productStock == 0) { // 재고가 0개라면
			return this.productNum + ". " + this.productName + " : " + this.productPrice + "[품절]"; // 품절 출력
		}
		return this.productNum + ". " + this.productName + " : " + this.productPrice + "[" + this.productStock + "]";
	}

	public int getProductNum() {
		return productNum;
	}

	public void setProductNum(int productNum) {
		this.productNum = productNum;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public int getProductPrice() {
		return productPrice;
	}

	public void setProductPrice(int productPrice) {
		this.productPrice = productPrice;
	}

	public int getProductStock() {
		return productStock;
	}

	public void setProductStock(int productStock) {
		this.productStock = productStock;
	}
}

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

		Scanner sc = new Scanner(System.in); 
		ArrayList<Product> data = new ArrayList<Product>(); // Product 클래스 객체 생성

		int numPk = 1; // 상품의 번호는 1부터 시작
		int action; // 메뉴 번호 입력 변수

		System.out.println("==============");
		System.out.println("1. 상품 목록 출력");
		System.out.println("2. 구매하기");
		System.out.println("3. 프로그램 종료");
		System.out.println("==============");
		System.out.println();
		System.out.print("사용할 메뉴를 선택하세요. ");
		action = sc.nextInt();
		while (true) {
			if (action == 3) { // 3. 프로그램종료
				System.out.println("프로그램을 종료합니다.");
				System.out.println();
				break;
			} else if (action == 1) { // 1. 상품목록출력 (재고없는상품은 [품절])
				System.out.println("=== 상품 목록 ===");
				for (Product product : data) { // ArrayList에 저장된 값들을 출력하기 위해 forEach문 사용
					System.out.println(product); // 저장된 값들 출력
				}
				System.out.println("상품 출력 완료 ! 메뉴로 돌아갑니다.");
				System.out.println();
			} else if (action == 2) { // 2. 구매하기
				System.out.println("=== 상품 목록 ===");
				for (Product product : data) { // 사용자가 구매를 눌렀을 시 메뉴를 보기 편하도록 상품 목록 출력
					System.out.println(product);
				}
				int cnt = 0; // 구매할 개수 0으로 초기화
				while (true) {
					System.out.println();
					System.out.print("구매할 상품의 번호를 입력하세요. ");
					int num = sc.nextInt();
					if (!(0 < num && num <= data.size())) {
						System.out.println("잘못 입력 하셨습니다. 다시 입력해주세요.");
						continue;
					}
					for (int i = 0; i < data.size(); i++) { // 지금까지 입력받은 값들이 있는 배열 리스트 안에
						if (num == data.get(i).getProductNum()) { // 혹시 지금 입력받은 번호가 배열 리스트에 있니 ?
							if (data.get(i).getProductStock() == 0) { // 혹시 재고가 0이라면
								System.out.println("재고가 없어서 메뉴로 돌아갑니다.");
								break;
							} else {
								System.out.println(data.get(i)); // 사용자가 입력한 상품
								System.out.println("위 상품을 구매하시겠습니까 ? ");
								System.out.println("1. Yes     2. No ");
								System.out.print("번호 입력) ");
								int isTrue = sc.nextInt();

								if (isTrue == 1) { // 상품을 구매하겠다면
									System.out.print("상품의 개수를 구매하실 만큼 입력하세요. ");
									cnt = sc.nextInt();

									int total = data.get(i).getProductPrice() * cnt; // 총 가격 연산
									System.out.println("상품의 개수는 " + cnt + "개이고, 가격은 " + total + "원 입니다.");
									System.out.println("1. 구매하기      2. 구매하지 않기 ");
									System.out.print("번호 입력) ");
									int isBuy = sc.nextInt();
									if (isBuy == 1) {
										data.get(i).sell(cnt); // Product 클래스의 sell() 메소드 사용
										break; // 이중 반복문 즉시 종료
									} else if (isBuy == 2) {
										System.out.println("구매하지 않아 메뉴로 돌아갑니다. ");
										break; // 메뉴로 이동
									}

								} else if (isTrue == 2) {
									System.out.println("구매하지 않아 메뉴로 돌아갑니다. ");
									break;
								}

							}
						}
					}
				}

			} else if (action == 1234) { // 관리자 모드 접근
				while (true) { // 관리자 모드 진입
					String name; // 입력 받을 이름 변수
					int price; // 입력 받을 가격 변수
					int stock; // 입력 받을 재고 변수

					System.out.println("관리자 프로그램을 실행합니다.");
					System.out.println();
					System.out.println("=== 관리자 프로그램 ===");
					System.out.println("1. 상품 추가");
					System.out.println("2. 상품 재고 변경");
					System.out.println("3. 상품 삭제");
					System.out.println("4. 관리자 프로그램 종료");
					System.out.println();
					System.out.print("사용할 메뉴를 선택해주세요. ");
					int action2 = sc.nextInt(); // 사용자의 입력값
					if (action2 == 4) { // 4. 관리자모드종료
						System.out.println("사용자 프로그램으로 돌아갑니다.");
						break;
					} else if (action2 == 1) { // 1. 상품추가
						System.out.print("추가할 상품의 이름을 입력하세요. ");
						name = sc.next();
						System.out.println(name + "으로 사용하시겠습니까 ? ");
						System.out.print("1. Yes      2. No ");

						System.out.print("상품의 가격을 입력하세요. ");
						price = sc.nextInt();

						System.out.print("상품의 재고를 입력하세요. ");
						stock = sc.nextInt();

						System.out.println(numPk + ". " + name + " " + price + "원 " + stock + "개 생성완료!"); // 가독성을 위해 출력
						data.add(new Product(numPk++, name, price, stock)); // 입력받은 값 저장
					} else if (action2 == 2) { // 2. 상품재고변경

						System.out.println("=== 상품 목록 ===");
						for (Product product : data) { // ArrayList에 저장된 값들을 출력하기 위해 forEach문 사용
							System.out.println(product); // 저장된 값들 출력
						}
						System.out.println();
						System.out.print("변경할 상품의 번호를 입력해주세요. ");
						int num = sc.nextInt();

						int i = 0;
						while (i < data.size()) { // 지금까지 입력받은 값들이 있는 배열 리스트 안에
							if (num == data.get(i).getProductNum()) { // 입력한 번호와 맞는 내 번호가 있니 ?
								System.out.println(data.get(i).getProductName() + "상품의 재고를 변경합니다. "); // 입력할 번호에 있는
								System.out.print("변경할 상품의 재고를 추가할만큼 입력해주세요. ");
								stock = sc.nextInt();

								data.get(i).changeProduct(stock); // 입력한 번호의 상품을 changeProduct()로 실행한다.
								break;
							}
						}
					} else if (action2 == 3) { // 3. 상품삭제
						int num;
						System.out.print("삭제할 상품의 번호를 입력해주세요. ");
						num = sc.nextInt();

						for (int i = 0; i < data.size(); i++) { // 지금까지 입력받은 값들이 있는 배열 리스트 안에
							if (num == data.get(i).getProductNum()) { // 혹시 지금 입력받은 번호가 배열 리스트에 있니 ?
								System.out.println(data.get(i).getProductName() + "상품 삭제 완료! ");
								data.remove(i); // 그번호의 상품 삭제하기
								break;
							}
						}
					}
				}
			}

		}
	}
}

 

다음 시간에는 유효성 검사 및 기능 검사를 추가로 포스팅할 예정이다.

728x90