자판기 프로그램
프로그램 개요
while (true) {
사용자에게 메뉴화면을 보여주어야함
메뉴화면을 본 사용자는 console에 사용할 메뉴를 입력
C는 V에게 입력값을 받아서,
어떤 M(기능)을 수행해야하는지 연결해줄예정
만약에 음료추가를 사용자가 선택했다면,
C는 M한테 음료추가를 부탁할 예정
M은 음료추가(C, insert())를 하기위해~
-음료의 이름, 음료의 가격, 음료의 재고를 필요로함
C는 이런 M의 상황을 알고,
V한테 부탁합니다.
V는 이름, 가격, 재고를 순서대로 사용자에게 입력받아옴
입력값 V -> C 넘겨줌
C는 입력값을 M한테 넘겨줌
만약에 음료목록출력을 선택했다면,
C가 M한테 R(selectAll())을 요청함
M은 selectAll()을 수행하고, 그 결과값을 C한테 줌
C는 결과값을 V한테 전달
V는 console 화면에 출력
만약에 구매를 선택했다면,
V는 사용자한테 뭐 살래? 물어봄
사용자는 console에 번호입력
V는 받은 번호를 C한테 줌
C는 M한테 U(update())를 요청
이때, 받은 번호를 M한테 전달함
M은 U 수행결과를 T or F로 C에게 반환해줌
C는 수행결과를 아니까,
수행결과에 맞는 화면을 V에게 요청함
만약에 삭제를 선택했다면,
V는 사용자한테 뭐 살래? 물어봄
사용자는 console에 번호입력
V는 받은 번호를 C한테 줌
C는 M한테 D(delete())를 요청
이때, 받은 번호를 M한테 전달함
M은 D 수행결과를 T or F로 C에게 반환해줌
C는 수행결과를 아니까,
수행결과 맞는 화면을 V에게 요청함
프로그램 종료
}
유의사항
한 곳에서 메서드 시그니처를 변경하게 되면 다른 파트에도 그 영향이 전해지게 됩니다. 어떤 요구 사항이 발생했을 때 코드의 여러 부분을 수정해야하는 상황이 생기는데, 이 상황은 프로그램이 높은 결합도와 낮은 응집도를 가지고 있다고 할 수 있습니다. 그래서 결합도를 낮춰야 유지보수에 용이합니다.
Model
package model;
import java.util.ArrayList;
// DAO의 CRUD(비즈니스 메서드, 핵심 로직)는
// 어떤 추가 요청사항에도 절대!
// "메서드 시그니처"가 변하지않도록 코드르 작성해야함!!!!!
// "메서드 시그니처"가 변경되면 다른 파트에 영향을 줘버림...
// '기능' 변경은 ㄱㅊ
// 결론) "메서드 시그니처"는 설계단계에서 절대로 변경되면 안됨!!!!!
public class DrinkDAO {
private static int PK=1001;
private ArrayList<DrinkVO> datas;
public DrinkDAO() {
datas=new ArrayList<DrinkVO>();
datas.add(new DrinkVO(PK++,"콜라",1200,3));
datas.add(new DrinkVO(PK++,"사이다",900,2));
datas.add(new DrinkVO(PK++,"환타",1500,1));
}
public boolean insert(DrinkVO vo) {
datas.add(new DrinkVO(PK++, vo.getName(), vo.getPrice(), vo.getCnt()));
return true;
}
public ArrayList<DrinkVO> selectAll(DrinkVO vo) {
if (vo.getName() == null) {
return datas;
} else {
ArrayList<DrinkVO> datas = new ArrayList<DrinkVO>();
for (DrinkVO data : this.datas) {
if (data.getName().contains(vo.getName())) {
datas.add(data);
}
}
return datas;
// 이름을보고,
// 새로운 datas를 만들ㅇ서,
// 이름을 가진 애들을 넣어서 반환
}
// 1. 전체목록출력 => 그냥 내가가진 멤버변수 datas 반환
// 2. 검색결과출력 => 이름을보고, 그 이름을 가진 애들을 반환
}
public DrinkVO selectOne(DrinkVO vo) { // PK
for (DrinkVO data :datas) {
if (data.getNum() == vo.getNum()) {
DrinkVO dVO = new DrinkVO(data.getNum(), data.getName(), data.getPrice(), data.getCnt());
return dVO;
// 실제 DB 데이터(==datas)를 전송 xxxxx
// 새로 vo객체를 new(객체화)해서 전송 O
}
}
System.out.println(" 로그: selectOne(): 해당상품없음");
return null;
}
// 오버로딩이 불가능한 기능일 경우,
// 기능이 매우 유사한 것이기때문에 내부 로직에서 분리하여 관리
// -> 유사한 기능끼리는 묶어서 관리하는 것이 용이하기 때문
// == 응집도를 높임 -> 유지보수에 용이
public boolean update(DrinkVO vo) {
for (DrinkVO data : datas) {
if (data.getNum() == vo.getNum()) {
// 구매할때에는 절대값이랑 내 재고랑 비교
if (vo.getCnt() < 0) { // 구매할떄
int cnt = vo.getCnt() * (-1); // 구매하려는 양
if (cnt > data.getCnt()) {
System.out.println(" 로그: update(): 재고없음");
return false;
}
}
data.setCnt(data.getCnt() + vo.getCnt());
return true;
}
}
System.out.println(" 로그: update(): 해당상품없음");
return false;
}
public boolean delete(DrinkVO vo) {
for (int i = 0; i < datas.size(); i++) {
if (datas.get(i).getNum() == vo.getNum()) {
datas.remove(i);
return true;
}
}
System.out.println(" 로그: delete(): 해당상품없음");
return false;
}
}
package model;
public class DrinkVO {
private int num;
private String name;
private int price;
private int cnt;
public DrinkVO(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 getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getCnt() {
return cnt;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
@Override
public String toString() {
String msg=num+"번 "+name+" "+price+"원 ";
if(this.cnt==0) {
msg+="[X]";
}
else {
msg+="["+cnt+"개]";
}
return msg;
}
@Override
public boolean equals(Object obj) {
DrinkVO drinkVO = (DrinkVO)obj;
if (this.num == drinkVO.num) {
return true;
}
return false;
}
}
View
package view;
import java.util.ArrayList;
import java.util.Scanner;
import model.DrinkVO;
public class DrinkView {
private static Scanner sc=new Scanner(System.in);
public int tryCatch() {
while(true) {
try {
System.out.print("입력) ");
int action=sc.nextInt();
return action;
}
catch(Exception e) {
sc.nextLine();
System.out.println("정수로 입력해주세요!");
}
}
}
public int printMenu() {
System.out.println("=== 자 판 기 ===");
System.out.println("1. 음료추가");
System.out.println("2. 음료목록출력");
System.out.println("3. 음료구매");
System.out.println("4. 음료제거");
System.out.println("5. 음료재고추가");
System.out.println("6. 음료검색"); // R -> selectAll(2개이상)
System.out.println("7. 프로그램 종료");
while (true) {
int action = tryCatch();
if(1 <= action && action <= 7) {
return action; // "유효성 검사" == 사용자의 입력값 검사
// : 사용자의 입력값에 대하여 자료형(타입),범위 등을 확인하는 것
}
}
}
public String getDrinkName() {
System.out.print("음료이름입력) ");
String name=sc.next();
return name;
}
public int getDrinkCnt() {
System.out.print("음료재고입력) ");
int cnt=sc.nextInt();
return cnt;
}
public int getDrinkPrice() {
System.out.print("음료가격입력) ");
int price=sc.nextInt();
return price;
}
public void printDrinkList(ArrayList<DrinkVO> datas) {
if (datas == null) {
System.out.println("음료가 없습니다.");
return;
}
for(DrinkVO v:datas) {
System.out.println(v);
}
}
public int getDrinkNum() {
System.out.print("음료번호입력) ");
int num=sc.nextInt();
return num;
}
public void printTrue() {
System.out.println("요청하신 서비스를 완료했습니다.");
}
public void printFalse() {
System.out.println("요청하신 서비스는 현재 이용이 어렵습니다.");
System.out.println("다음에 다시 이용해주시기 바랍니다.");
}
public void printEnd() {
System.out.println("프로그램 종료...");
}
}
Controller
package ctrl;
import java.util.ArrayList;
import model.DrinkDAO;
import model.DrinkVO;
import view.DrinkView;
public class DrinkCtrl {
private DrinkView view;
private DrinkDAO dao;
public DrinkCtrl() {
view=new DrinkView();
dao=new DrinkDAO();
}
public void startApp() {
while (true) {
System.out.println(" 로그: 사용자가 새로 입장합니다.");
// 로그
// : 확인을 하는 것
// : 실제 서비스에서는 출력 xxx
ArrayList<DrinkVO> cart = new ArrayList<DrinkVO>();
while (true) {
int action = view.printMenu();
if (action == 1) {
String name = view.getDrinkName();
int price = view.getDrinkPrice();
int cnt = view.getDrinkCnt();
DrinkVO vo = new DrinkVO(0, name, price, cnt);
// DAO의 CRUD에게 전달해야하는 값만 설정
// 전달하지않아도되는 값들은 0, null 등으로 설정
if (dao.insert(vo)) {
view.printTrue();
} else {
view.printFalse();
}
} else if (action == 2) {
ArrayList<DrinkVO> datas = dao.selectAll(new DrinkVO(0, null, 0, 0));
view.printDrinkList(datas);
} else if (action == 3) {
int num = view.getDrinkNum();
// int cnt = view.getDrinkCnt();
int cnt = 1;
DrinkVO vo = new DrinkVO(num, null, 0, -cnt);
if (dao.update(vo)) {
// 구매에 성공했을때에만 장바구니에 해당 상품을 추가
DrinkVO data = dao.selectOne(vo);
data.setCnt(cnt); // PK, name, price는 자판기에 저장된 상품 정보로 가능하지만
// cnt는 사용자가 입력했던 정보로 변경해야함!
boolean flag = false;
int index = 0;
for (int i = 0; i < cart.size(); i++) {
if (data.equals(cart.get(i))) {
index = i;
flag = true;
}
}
if (flag) {
cart.get(index).setCnt(cart.get(index).getCnt() + cnt);
} else {
cart.add(data); // 장바구니.add(내가 구매한 상품);
}
view.printDrinkList(cart);
view.printTrue();
} else {
view.printFalse();
}
} else if (action == 4) {
int num = view.getDrinkNum();
DrinkVO vo = new DrinkVO(num, null, 0, 0);
if (dao.delete(vo)) {
view.printTrue();
} else {
view.printFalse();
}
} else if (action == 5) {
int num = view.getDrinkNum();
int cnt = view.getDrinkCnt();
DrinkVO vo = new DrinkVO(num, null, 0, cnt);
if (dao.update(vo)) {
view.printTrue();
} else {
view.printFalse();
}
} else if (action == 6) {
String name = view.getDrinkName();
ArrayList<DrinkVO> datas = dao.selectAll(new DrinkVO(0, name, 0, 0));
view.printDrinkList(datas);
} else if (action == 7) {
view.printEnd();
break;
}
}
System.out.println(" 로그: 사용자가 종료했습니다.");
cart.clear();
}
}
}
Client
package client;
import ctrl.DrinkCtrl;
public class Client {
public static void main(String[] args) {
DrinkCtrl app=new DrinkCtrl();
app.startApp();
}
}
GitHub
https://github.com/Qkrwnsgus0522/Java