열심히 끝까지

[코딩 예시] - 6/28 MVC 자판기 프로그램 + 관리자 추가 과제 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(과제)

[코딩 예시] - 6/28 MVC 자판기 프로그램 + 관리자 추가 과제

노유림 2022. 6. 28. 16:45

[자판기 프로그램] MVC 
[설계]-------------
주제 : 자판기 프로그램 with MVC
 
요구사항 
      - 관리자 모드
      - 재고 데이터
      - MVC 역할분담을 제대로
      - 각 파트에 2.2.2
      - 문서화(버전 관리) + 회의 내용 기록
      
Model 파트---------
   - VO : 데이터 정의
         - 자판기 안의 제품
                 : PK(중요!!)
                 : 제품 이름
                 : 제품 가격
                 : 재고 데이터
               
   - DAO : 비즈니스 메서드(핵심로직, CRUD)
               무슨 행동을 할지 정의
               VO를 가지고 어떤 동작을 할 지 고민      
         - 데이터 추가(C) : Insert
                  : 새로운 음료 혹은 재고를 추가하는 행위
                        >> "관리자"의 작업
         - 데이터를 출력(보여주는 행위 V)
                  : 음료를 보여주는 행위
                        >> 서비스
                  : 음료를 구매하는 행위
                        >> 서비스(행위)
         - 데이터를 삭제하는 행위(D)
                  : 기존의 음료 메뉴를 삭제하는 행우
                        >> 관리자

         - 데이터를 검색하는 행위
                  : 음료를 검색해서 찾는 행위
                        >> 서비스
                 > 근데 이번에 안다룸.. 검색하는 서비스는!

View 파트------------
        - UI/UX
          User Flow
          사용자의 편의성을 도모
          사용자가 입력한 값을 유효성 검사
          사용자만을 위한 파트이기에 메뉴 추가는 안들어간다!!

         1) 전체메뉴
             ===자판기===  
             1. 메뉴확인 2. 구매 3. 종료
         2) 1번을 눌렀을 때 사용자에게 제공될 화면
                : 현재 DB(음료들을 N개 저장할 객체)에 존재하는 메뉴들을 출력
                                ㄴ> 컬렉션 : ArrayList(배열리스트)
         3) 2번을 눌렀을 때 사용자에게 제공될 화면(1) 
                : ㅁㅁ 구매 완료되었습니다!!
         4) 2번을 눌렀을 때 사용자에게 제공될 화면(2) 
                : ㅁㅁ 재고가 없습니다...
                >> 버튼을 눌렀을 때, 재고가 없는 친구라고 띄어도 됨
         5) 3번을 눌렀을 때 사용자에게 제공될 화면
                : 프로그램이 종료됩니다...

Controller 파트-----------                   
     - Model - View 연결다리 역할
          : View_1()이 실행
               if 1번을 눌렀다면? View_2();
                  2번을 눌렀다면? View_3() or View_4()
                          >> Model을 참고하여 누가 나올지를 결정!!
                  3번을 눌렀다면? View_5();
                  4, 0, -1 이런 거 눌렀다면?(1,2,3이 아닌 다른 값이 들어오면?)
                        >> View 작업자에게 요청
                            : 근데 controller가 짜고 있다면..?    
                               > 그건 나쁜 행위..!!!
                               > 외부로 옮겨지게 되면 데이터를 많이 잡아먹는다.


------------------실제 사례
1) M에서 기존의 음료메뉴 삭제() 구현
               >> 내부 구현 로직이 이상한 로직으로 구현된 상태!!



2) M에서 기존의 음료메뉴 삭제() 잘 구현
               >> Controller에서 Model을 불러오는 과정에서 잘못 호출을 함!

동일한 문제인데 누가 어떤 잘못을 했는지에 따라
누가 고치는지 달라짐!!!
맡은 바를 잘 살펴볼 것!!!
    >> 잘 판단할 줄 알아야 한다!!


--------강사님의 자판기 프로젝트 코딩------
------modelVO----------

package model;
// 웹 개발에서, 일반적으로 기본생성자를 사용하여 VO를 생성(new)
public class ProductVO {
	private int num; // PK
	private String name;
	private int cnt; // 재고 데이터
	private int price;
	public ProductVO(int num, String name, int price) {
		this(num, name, price, 0);
		// 재고 지정이 안되어 있으면 0으로 디폴트
	}
	public ProductVO(int num, String name, int price, int cnt) {
		this.num = num;
		this.name = name;
		this.price = price;
		this.cnt = cnt;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getCnt() {
		return cnt;
	}
	public void setCnt(int cnt) {
		this.cnt = cnt;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	@Override
	public String toString() {
		return "ProductVO [num=" + num + ", name=" + name + ", cnt=" + cnt + ", price=" + price + "]";
	}
}

 

-----ModelDAO---------

package model;
import java.util.ArrayList;
// CRUD
public class ProductDAO {
	// DB를 대체하는 컬렉션(배열리스트)
	ArrayList<ProductVO> datas;
	private int pk = 101; // 후위증감 연산을 선호한다
	// 어딘가에서 DAO 사용할텐데, 
	// DAO가 생성되면 그 즉시 datas도 생성되게끔 하고 싶다!
	// == DAO의 멤버변수인 datas도 값을 가질 수 있게 만들고 싶어요~
	// 생성자를 써야한다.
	public ProductDAO() { // default로 만들면 다른 패키지에서 쓸 수 없다...
		// 앞으로 public을 붙여서 사용!
		datas= new ArrayList<ProductVO>();
		// 초기데이터(혹은 샘플 데이터)
		datas.add(new ProductVO(pk++, "콜라", 1200));
		datas.add(new ProductVO(pk++, "사이다", 900, 5));
		datas.add(new ProductVO(pk++, "환타", 800, 2));
	}
	// 관리자
	// 새로운 음료 추가
	// 음료 재고 추가
	// 음료 삭제
	// 사용자(서비스)
	// 음료 출력
	// 음료 구매
	public ArrayList<ProductVO> selectAll() { // getAll()
		//DB에서는 선택하는 행위를 SelectAll()로 쓰이는 경우가 많다.
		// 여기서 출력을 한다?? 잘못된거다!
		// 직접 로직을 구현하는 경우가 있는데 그거 잘못된것이다!!
		// View측에서 무엇을 필요로 할 지 고려!
		System.out.println("로그 : selectAll()");
		return datas;
	}
	public ProductVO selectOne(int num) { // getOne() R에 해당
		for(int i = 0; i < datas.size(); i++) {
			if(num==datas.get(i).getNum()) {
				System.out.println("로그 : " + datas.get(i) + " 반환");
				return datas.get(i);
			}
		}
		System.out.println("로그 : 반환xxx -> 확인 필요!");
		return null; // 만날 확률이 거의 없다.
		// 이상한 숫자가 들어오게 되면 null값을 되돌려준다.
		// 이상한 숫자가 들어올 일이 없기 때문이다.
		// 유효성검사를 View가 해줄 것이다.
	}
	// 음료 구매
	// 사용자가 pk 입력
	// pk에 해당하는 음료를 출력
	// 구매 시도 시 음료의 재고 -- 
	public boolean update(ProductVO vo) { // U에 해당
		// 실무에서는 다르게 작성하기도 하다(void도 하지만 boolean값도 쓰인다
		// update의 성공 여부
		if(vo.getCnt()==0) {
			System.out.println("로그 : " + vo.getNum() + " 재고가 없습니다.");
			return false;
		}
		vo.setCnt(vo.getCnt()-1); 
		System.out.println("로그 : " + vo.getNum() + " 구매 완료!");
		return true;
	}
}
// 이걸로 model의 역할을 끝!

 

-----View-----------

package view;
import java.util.ArrayList;
import java.util.Scanner;
import model.ProductVO;
public class ProductView {
	Scanner sc = new Scanner(System.in);
	public int action;
	public void startView() {
		while(true) { // 유효성 검사 -> 꼼꼼하게 작업해보기!
			System.out.println("=== 자판기 ===");
			System.out.println("1.메뉴확인 2.구매 3.종료");
			System.out.print("입력) ");
			action = sc.nextInt();
			if(action >= 1 && action <=3 || action == 1234) { // 관리자모드 1234
				break;
			}
			System.out.println("범위외입력!");
		}
	}
	public void func1(ArrayList<ProductVO> datas) {
		for(int i = 0; i < datas.size(); i++) {
			System.out.println((i+1)+"번 메뉴 " + datas.get(i).getName());
		}
	}
	public void func2(ArrayList<ProductVO> datas) {
		for(int i = 0; i < datas.size(); i++) {
			System.out.print((i+1)+"번 메뉴 " + datas.get(i).getName());
			if(datas.get(i).getCnt()==0) {
				System.out.println("x");
				continue;
			}
			System.out.println(datas.get(i).getCnt());
		}
		while(true) {
			System.out.print("메뉴 입력 ) ");
			action = sc.nextInt();
			if(1<=action && action <= datas.size()) {
				break;
			}
			System.out.println("상품번호 확인 후 다시 입력해주세요!");
		}
		// action += 100; -> Controller 에서 해야한다고 강사님은 생각!
		// 상품번호가 몇번인지 모르는게 맞기 때문에!
	}
	public void funcT(ProductVO vo) {
		System.out.println(vo.getName() + "구매완료!");
	}
	public void funcF(ProductVO vo) {
		System.out.println(vo.getName() + " 재고가 없습니다...");
	}
	public void func3() {
		System.out.println("프로그램이 종료됩니다");
		for(int i = 0; i < 5; i++) {
			System.out.println(".");
			try {
				Thread.sleep(1000); // 1000당 1초 재운다 == sleep
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
		}
	}
}

 

---------Controller-----------

package controller;
import model.ProductDAO;
import model.ProductVO;
import view.ProductView;
public class ProductController {
	ProductDAO model;
	ProductView view;
	public ProductController() {
		model = new ProductDAO();
		view = new ProductView();
	}
	public void startApp() {
		while(true) {
			view.startView();
			if(view.action==1) {
				view.func1(model.selectAll());
			}
			else if(view.action==2) {
				view.func2(model.selectAll());
				// 사용자가 먹고 싶은 메뉴의 번호를 입력햇는데,
				// C에서 [view.action]
				// C 에서는 사용자가 입력한 메뉴의 번호를 view.action으로 참조 가능하고,
				// M은 pk를 입력받으면 상품객체를 줄 준비가 되어있습니다.
				int num =view.action;// V에서 사용자가 입력한 메뉴 번호 pk 해당
				ProductVO vo = model.selectOne(num+ 100);
				// pk를 넣으면 해당하는 상품을 반환하는 M의 selectOne()메서드
				boolean flag = model.update(vo);
				// M은 반환받은(==사용자가 선택한) 객체의 재고를 --
				// boolean flag=model.update(model.selectOne(view.action+100)); // 상품객체 전달
				if(flag) {
					view.funcT(vo);
				}
				else {
					view.funcF(vo);
				}
			}
			else if(view.action==3) {
				view.func3();
				break;
			}
		}
	}
}

 

 

-------Client-----------

package client;
import controller.ProductController;
public class Client {
	public static void main(String[] args) {
		// 지금까지 만든 APP을 수행시킬 공간
		// main()이 존재함
		ProductController app = new ProductController();
		app.startApp();
	}
}

 

 

+ 과제

[V]
1. === 관리자 모드 ===
 1) 음료 추가
 2) 음료 재고 추가
 3) 음료 삭제
 
2. 추가할 음료의 정보를 입력하세요
3. 추가할 음료의 번호와 개수를 입력하세요
4. 삭제할 음료의 번호를 입력하세요.

[M]

[C]

 

-----------------> 관리자 추가해보기