[[TableOfContents]] === 원칙 === 다음과 같은 2개의 원칙만 적용해서 수정해봤습니다. 1. 명확하지 않는 변수/함수&메소드 이름에 대해 - 이름을 다르게 바꿔준다. 또는 무엇을 하기 위한 것인가에 입각, 함수/메소드 로 추출한다. [[BR]] 2. 소위 magic number (ex : 배열의 범위를 설정하는 숫자들) 라 불리는 것들에 대해 - const 변수 선언[[BR]] 3. 긴 메소드 - 함수 & 메소드를 따로 추출. 즉, 하나의 함수 내에서 하는 일들이 많다고 생각될 때. [[BR]] 4. 중복 - 중복되는 부분에 대해 함수 & 메소드로 추출.[[BR]] 여기서는 저 위의 1-4번 원칙만 생각해 보겠습니다. 일단 이 코드가 제대로 돌아간다는 가정하에서 수정합니다. (문제는 제대로 고쳐졌는지 확인할 길이 적다는. -_-;) === menu 추출 : 3번 원칙 === {{{~cpp void printMenu () { cout << "\n자판기 입니다\n"; cout << "1.돈을 넣는다\n"; cout << "2.물건을 산다\n"; cout << "3.돈을 거술러 받는다\n"; cout << "4.음료수를 채운다\n"; cout << "0.종료한다\n"; cout << "메뉴를 선택하세요 : "; } }}} === while loop 에서의 조건식 - 1번 === {{{~cpp bool isEndMenu (int choice) { return choice != 0; } }}} {{{~cpp while(isEndMenu (choice)) { printMenu (); cin >> choice; . . }}} === choice != 0 : 2번 === {{{~cpp enum { MENU_END = 0, }; }}} {{{~cpp bool isEndMenu (int choice) { return choice != MENU_END; } }}} === MENU 부분에 대해서 : 2번 === {{{~cpp enum { MENU_END = 0, MENU_GET_MONEY, MENU_BUY, MENU_TAKEBACK_MONEY, MENU_INSERT_DRINK }; }}} {{{~cpp switch(choice) { case MENU_GET_MONEY: VendingMachine.GetMoney(); break; case MENU_BUY: VendingMachine.Buy(); break; case MENU_TAKEBACK_MONEY: VendingMachine.TakeBackMoney(); break; case MENU_INSERT_DRINK: VendingMachine.InsertDrink(); break; case MENU_END: cout << "자판기를 종료합니다!!\n\n"; break; } }}} === MENU 선택 부분과 관련(choice >= 0 && choice <= 4), 잘못된 메뉴 선택 골라주기 : 1, 2번 === {{{~cpp bool isValidMenu (int choice) { return choice >= 0 && choice <= 4; } }}} 여기에 2번을 다시 적용해주면 {{{~cpp bool isValidMenu (int choice) { return choice >= MENU_END && choice <= MENU_INSERT_DRINK; } }}} 근데.. 좀 명확해 보이진 않는군요. enum 에서 설정된 것을 재정의해주면 {{{~cpp enum { MENU_ENDCODE = 0, MENU_START = 0, MENU_GET_MONEY, MENU_BUY, MENU_TAKEBACK_MONEY, MENU_INSERT_DRINK, MENU_END = MENU_INSERT_DRINK }; }}} MENU_END 뜻이 달라졌으므로, 앞에서 MENU_END를 썼었던 다른 것들도 고칩니다. {{{~cpp case MENU_ENDCODE: cout << "자판기를 종료합니다!!\n\n"; break; } }}} {{{~cpp bool isEndMenu (int choice) { return choice != MENU_ENDCODE; } }}} 그러면, {{{~cpp isValidMenu}}} 를 다음과 같이 고칠 수 있습니다. (써놓고 보니 그리 맘에 들진 않지만, 일단 이정도만 해두겠습니다. -_-;) {{{~cpp bool isValidMenu (int choice) { return choice >= MENU_START && choice <= MENU_END; } }}} === Menu 의 부분 - 1번 원칙 === {{{~cpp case MENU_ENDCODE: VendingMachine.EndMachine(); break; } } else VendingMachine.PrintErrorMessage (); } }}} 솔직히 이부분이 좋지 않은 것이.. Vending Machine 내에서 UI 부분이 확실하게 추출되지 않았다는 점입니다. (만일 Requirement 가 변경되어서, MFC 그래픽 버전으로 만든다면? 디자인이 잘 된다면, Vending Machine 쪽의 코드의 수정이 거의 없이 UI 코드만 '추가' 될 겁니다. 이는 기존 Vending Machine 코드쪽의 '변경'을 의미하지 않습니다.) 하지만 이건 추후에 Vending Machine 에서 메소드를 다른 클래스에게로 이양시켜주면서 UI 부분과 관련한 클래스를 추출해 낼 수 있을 것 같다고 생각합니다. 여기서는 추후에 진행하도록 하겠습니다. 디자인을 할때에 보통 Input / Output 은 요구사항이 자주 바뀌므로 일단 메인 Vending Machine 코드가 작성되고 난 뒤, Vending Machine 의 인터페이스에 맞춰서 Input / Output 코드를 나중에 작성하는 것이 좋습니다. === Vending Machine 의 초기화 부분 - 4번 원칙 === {{{~cpp const int DRINKNAME_MAXLENGTH = 255; const int TOTAL_DRINK_TYPE = 5; }}} {{{~cpp vending_machine::vending_machine() { money = temp_money = 0; select_money = 1; max_num = TOTAL_DRINK_TYPE; char drinkNames[TOTAL_DRINK_TYPE][DRINKNAME_MAXLENGTH] = {"coke", "juice", "tea", "cofee", "milk"}; int price[TOTAL_DRINK_TYPE] = {400, 600, 500, 450, 350}; for (int i=0; i using namespace std; enum { MENU_ENDCODE = 0, MENU_START = 0, MENU_GET_MONEY, MENU_BUY, MENU_TAKEBACK_MONEY, MENU_INSERT_DRINK, MENU_END = MENU_INSERT_DRINK }; const int DRINKNAME_MAXLENGTH = 255; const int TOTAL_DRINK_TYPE = 5; class vending_machine { private: int money; int temp_money; int select_money, select_drink, insert_amount; struct drink { char name[DRINKNAME_MAXLENGTH]; int price, amount; }; drink s_drink[5]; int max_num; public: vending_machine(); void GetMoney(); void Buy(); void TakeBackMoney(); void InsertDrink(); void EndMachine(); void PrintErrorMessage (); }; vending_machine::vending_machine() { money = temp_money = 0; select_money = 1; max_num = TOTAL_DRINK_TYPE; char drinkNames[TOTAL_DRINK_TYPE][DRINKNAME_MAXLENGTH] = {"coke", "juice", "tea", "cofee", "milk"}; int price[TOTAL_DRINK_TYPE] = {400, 600, 500, 450, 350}; for (int i=0; i> temp_money; if(temp_money == 10 || temp_money == 50 || temp_money == 100 || temp_money == 500 || temp_money == 1000) money = money + temp_money; else cout << "10, 50, 100, 500, 1000만 가능합니다. 다시 시작해주세요\n"; cout << money << "원을 넣었습니다\n"; } void vending_machine::Buy() { cout << "음료수\t\t가격\t수량\n"; cout << "------------------------------------\n"; for(int i = 0 ; i < max_num ; i++) cout << i + 1 << "." << s_drink[i].name << "\t\t" << s_drink[i].price << "\t" << s_drink[i].amount << "\n"; cout << "\n현재 " << money << "원이 있어요\n"; cout << "원하는 음료수를 선택하세요 : "; cin >> select_drink; switch(select_drink) { case 1: if((money - s_drink[select_drink - 1].price) >= 0 && s_drink[select_drink - 1].amount >= 1) { s_drink[select_drink - 1].amount--; money = money - s_drink[select_drink - 1].price; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; break; case 2: if((money - s_drink[select_drink - 1].price) >= 0 && s_drink[select_drink - 1].amount >= 1) { s_drink[select_drink - 1].amount--; money = money - s_drink[select_drink - 1].price; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; break; case 3: if((money - s_drink[select_drink - 1].price) >= 0 && s_drink[select_drink - 1].amount >= 1) { s_drink[select_drink - 1].amount--; money = money - s_drink[select_drink - 1].price; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; break; case 4: if((money - s_drink[select_drink - 1].price) >= 0 && s_drink[select_drink - 1].amount >= 1) { s_drink[select_drink - 1].amount--; money = money - s_drink[select_drink - 1].price; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; break; case 5: if((money - s_drink[select_drink - 1].price) >= 0 && s_drink[select_drink - 1].amount >= 1) { s_drink[select_drink - 1].amount--; money = money - s_drink[select_drink - 1].price; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; break; } cout << money << "원이 남았어요\n"; } void vending_machine::TakeBackMoney() { cout << "거스름돈" << money << "원을 돌려드립니다\n"; money = 0; } void vending_machine::InsertDrink() { for(int i = 0 ; i < max_num ; i++) cout << i + 1 << "." << s_drink[i].name << "\t" << s_drink[i].amount << "\n"; cout << "채우길 원하는 음료수를 선택하세요 : "; cin >> select_drink; cout << "채우길 원하는 음료수 수량을 입력해주세요 : "; cin >> insert_amount; switch(select_drink) { case 1: s_drink[select_drink - 1].amount += insert_amount; break; case 2: s_drink[select_drink - 1].amount += insert_amount; break; case 3: s_drink[select_drink - 1].amount += insert_amount; break; case 4: s_drink[select_drink - 1].amount += insert_amount; break; case 5: s_drink[select_drink - 1].amount += insert_amount; break; } cout << "음료수를 채웠습니다\n"; for(i = 0 ; i < max_num ; i++) cout << i + 1 << "." << s_drink[i].name << "\t" << s_drink[i].amount << "\n"; } void vending_machine::EndMachine() { cout << "자판기를 종료합니다!!\n\n"; } void vending_machine::PrintErrorMessage () { cout << "잘못된 메뉴 선택입니다. 메뉴를 다시 입력해주세요\n"; } void printMenu () { cout << "\n자판기 입니다\n"; cout << "1.돈을 넣는다\n"; cout << "2.물건을 산다\n"; cout << "3.돈을 거술러 받는다\n"; cout << "4.음료수를 채운다\n"; cout << "0.종료한다\n"; cout << "메뉴를 선택하세요 : "; } bool isEndMenu (int choice) { return choice != MENU_ENDCODE; } bool isValidMenu (int choice) { return choice >= MENU_START && choice <= MENU_END; } int main() { vending_machine VendingMachine; int choice = -1; while(isEndMenu (choice)) { printMenu (); cin >> choice; if(isValidMenu (choice)) { switch(choice) { case MENU_GET_MONEY: VendingMachine.GetMoney(); break; case MENU_BUY: VendingMachine.Buy(); break; case MENU_TAKEBACK_MONEY: VendingMachine.TakeBackMoney(); break; case MENU_INSERT_DRINK: VendingMachine.InsertDrink(); break; case MENU_ENDCODE: VendingMachine.EndMachine(); break; } } else VendingMachine.PrintErrorMessage (); } return 0; } }}} === vending_machine::GetMoney () - 1, 3, 4번 원칙 === '무엇을 하는가' 라고 할때 InsertMoney 또는 InsertCoin 이 더 정확한 표현이라 생각되어집니다. 그리고, 역시 하는 일에 대해서 메소드로 추출함으로서 comment 를 대신 할 수 있습니다. {{{~cpp bool vending_machine::isValidMoney (int money) { return (temp_money == 10 || temp_money == 50 || temp_money == 100 || temp_money == 500 || temp_money == 1000); } void vending_machine::InsertMoney() { cout << "돈을 넣으세요. 10, 50, 100, 500, 1000만 가능 : "; cin >> temp_money; if (isValidMoney (temp_money)) { money = money + temp_money; } else cout << "10, 50, 100, 500, 1000만 가능합니다. 다시 시작해주세요\n"; cout << money << "원을 넣었습니다\n"; } }}} 그리고, 메소드로 추출하면 좋은점이, 코드를 고칠 부분을 메소드 내로 시야의 폭을 줄일 수 있습니다. 작은 메소드라도 추출해두면 나중에 다시 메소드를 모으거나, 중복을 없애기가 편리합니다. {{{~cpp bool vending_machine::isValidMoney (int money) { int validMoneys[5] = {10, 50, 100, 500, 1000}; for (int i=0;i<5;i++) { if (money == validMoney[i]) return true; } return false; } }}} 단, 이러한 중복줄이기 & 일반화는 중복이 발생되었을때 (2 or 3 strike) 해주는 것이 쉽습니다. 처음부터 모든 중복될 부분을 다 예측해 낼 수는 없습니다. 이 일부터 시작, 더 극단적인 예를 든다면 다음과 같이도 할 수 있지만, 꼭 할 필요는 없습니다. (그대신 시도해보면 재미있습니다) 일단 넓게 넓게 보는 것이 더 좋기 때문에. {{{~cpp const int validMoney[5] = {10, 50, 100, 500, 1000}; void vending_machine::printInsertCoinMenu () { cout << "돈을 넣으세요. 10, 50, 100, 500, 1000만 가능 : "; } void vending_machine::printErrorInvalidCoinMessage () { cout << "10, 50, 100, 500, 1000만 가능합니다. 다시 시작해주세요\n"; } void vending_machine::printCurrentMoney () { cout << money << "원을 넣었습니다\n"; } bool vending_machine::isValidMoney (int money) { for (int i=0;i<5;i++) { if (money == validMoney[i]) return true; } return false; } void vending_machine::InsertMoney() { printInsertCoinMenu (); cin >> temp_money; if (isValidMoney (temp_money)) { money = money + temp_money; printCurrentMoney (); } else printErrorInvalidCoinMessage (); } }}} 이것을 한번 더 중복을 줄이면 {{{~cpp void vending_machine::printInsertCoinMenu () { cout << "돈을 넣으세요. "; for (int i=0;i<4;i++) { cout << validMoneys[i] << "," } cout << valiMoneys[4] << "만 가능 : "; } }}} === temp_money - 4번 === temp_money 가 하는 일을 보면 한가지 일만 합니다. {{{~cpp void vending_machine::InsertMoney() { printInsertCoinMenu (); cin >> temp_money; if (isValidMoney (temp_money)) { money = money + temp_money; printCurrentMoney (); } else printErrorInvalidCoinMessage (); } }}} 이 이외엔 쓰이지 않지만, private 멤버로 있습니다. 이러한 입력을 받기 위한 임시변수는 그냥 멤버에서 없애주면 됩니다. {{{~cpp void vending_machine::InsertMoney() { int temp_money = 0; printInsertCoinMenu (); cin >> temp_money; if (isValidMoney (temp_money)) { money = money + temp_money; printCurrentMoney (); } else printErrorInvalidCoinMessage (); } }}} === vending_machine::Buy () - 1,3,4 === 1단계 - menu 부분 프린트 추출 & i -> drinkIndex 로 변경. {{{~cpp void vending_machine::printBuyMenu () { cout << "음료수\t\t가격\t수량\n"; cout << "------------------------------------\n"; for(int drinkIndex = 0 ; drinkIndex < max_num ; drinkIndex++) cout << drinkIndex + 1 << "." << s_drink[drinkIndex].name << "\t\t" << s_drink[drinkIndex].price << "\t" << s_drink[drinkIndex].amount << "\n"; cout << "\n현재 " << money << "원이 있어요\n"; cout << "원하는 음료수를 선택하세요 : "; } void vending_machine::Buy() { printBuyMenu (); . . }}} 2단계 - switch & case 이 부분에 대해서 이미 일반화 공식을 만들었음에도 불구하고 불필요한 switch & case 문이 있습니다. 이 부분에 대해서는 많은 코드를 줄일 수 있겠습니다. {{{~cpp void vending_machine::Buy() { printBuyMenu (); cin >> select_drink; if((money - s_drink[select_drink-1].price) >= 0 && s_drink[select_drink-1].amount >= 1) { s_drink[select_drink-1].amount--; money = money - s_drink[select_drink-1].price; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; cout << money << "원이 남았어요\n"; } }}} 그리고, select_drink-1 식으로 쓴 것이 많은데, 이 이유는 아마 번호를 1,2,3,4 ... 로 찍기 위함일 것입니다. 그리고 select_drink 또한 vending_machine 의 멤버인데, 특별히 하는 일이 없는 한 지역변수로 두는것이 낫습니다. === vending_machine::InsertDrink - 3,4 === {{{~cpp void vending_machine::InsertDrink() { int select_drink; int insert_amount; printCurrentDrinkStatus (); cout << "채우길 원하는 음료수를 선택하세요 : "; cin >> select_drink; cout << "채우길 원하는 음료수 수량을 입력해주세요 : "; cin >> insert_amount; if (select_drink-1 > 0 && select_drink-1 <=5) s_drink[select_drink-1].amount += insert_amount; cout << "음료수를 채웠습니다\n"; printCurrentDrinkStatus (); } }}} === 중간 소스 === {{{~cpp #include using namespace std; enum { MENU_ENDCODE = 0, MENU_START = 0, MENU_GET_MONEY, MENU_BUY, MENU_TAKEBACK_MONEY, MENU_INSERT_DRINK, MENU_END = MENU_INSERT_DRINK }; const int DRINKNAME_MAXLENGTH = 255; const int TOTAL_DRINK_TYPE = 5; const int validMoney[5] = {10, 50, 100, 500, 1000}; class vending_machine { private: int money; struct drink { char name[DRINKNAME_MAXLENGTH]; int price, amount; }; drink s_drink[TOTAL_DRINK_TYPE]; int max_num; public: vending_machine(); void InsertMoney(); void Buy(); void TakeBackMoney(); void InsertDrink(); void EndMachine(); bool isValidMoney (int money); void PrintErrorMessage (); void PrintErrorInvalidCoinMessage (); void PrintInsertCoinMenu(); void PrintCurrentMoney (); void PrintBuyMenu (); void PrintCurrentDrinkStatus (); }; vending_machine::vending_machine() { money = 0; max_num = TOTAL_DRINK_TYPE; char drinkNames[TOTAL_DRINK_TYPE][DRINKNAME_MAXLENGTH] = {"coke", "juice", "tea", "cofee", "milk"}; int price[TOTAL_DRINK_TYPE] = {400, 600, 500, 450, 350}; for (int i=0; i> temp_money; if (isValidMoney (temp_money)) { money = money + temp_money; PrintCurrentMoney (); } else PrintErrorInvalidCoinMessage (); } void vending_machine::PrintBuyMenu () { cout << "음료수\t\t가격\t수량\n"; cout << "------------------------------------\n"; for(int drinkIndex = 0 ; drinkIndex < max_num ; drinkIndex++) cout << drinkIndex + 1 << "." << s_drink[drinkIndex].name << "\t\t" << s_drink[drinkIndex].price << "\t" << s_drink[drinkIndex].amount << "\n"; cout << "\n현재 " << money << "원이 있어요\n"; cout << "원하는 음료수를 선택하세요 : "; } void vending_machine::Buy() { PrintBuyMenu (); int select_drink; cin >> select_drink; if((money - s_drink[select_drink-1].price) >= 0 && s_drink[select_drink-1].amount >= 1) { s_drink[select_drink-1].amount--; money = money - s_drink[select_drink-1].price; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; cout << money << "원이 남았어요\n"; } void vending_machine::TakeBackMoney() { cout << "거스름돈" << money << "원을 돌려드립니다\n"; money = 0; } void vending_machine::PrintCurrentDrinkStatus () { for(int drinkIndex = 0 ; drinkIndex < max_num ; drinkIndex++) cout << drinkIndex + 1 << "." << s_drink[drinkIndex].name << "\t" << s_drink[drinkIndex].amount << "\n"; } void vending_machine::InsertDrink() { int select_drink; int insert_amount; PrintCurrentDrinkStatus (); cout << "채우길 원하는 음료수를 선택하세요 : "; cin >> select_drink; cout << "채우길 원하는 음료수 수량을 입력해주세요 : "; cin >> insert_amount; if (select_drink-1 > 0 && select_drink-1 <=5) s_drink[select_drink-1].amount += insert_amount; cout << "음료수를 채웠습니다\n"; PrintCurrentDrinkStatus (); } void vending_machine::EndMachine() { cout << "자판기를 종료합니다!!\n\n"; } void vending_machine::PrintErrorMessage () { cout << "잘못된 메뉴 선택입니다. 메뉴를 다시 입력해주세요\n"; } void PrintMenu () { cout << "\n자판기 입니다\n"; cout << "1.돈을 넣는다\n"; cout << "2.물건을 산다\n"; cout << "3.돈을 거술러 받는다\n"; cout << "4.음료수를 채운다\n"; cout << "0.종료한다\n"; cout << "메뉴를 선택하세요 : "; } bool isEndMenu (int choice) { return choice != MENU_ENDCODE; } bool isValidMenu (int choice) { return choice >= MENU_START && choice <= MENU_END; } void vending_machine::Run () { int choice = -1; while(isEndMenu (choice)) { PrintMenu (); cin >> choice; if(isValidMenu (choice)) { switch(choice) { case MENU_GET_MONEY: InsertMoney(); break; case MENU_BUY: Buy(); break; case MENU_TAKEBACK_MONEY: TakeBackMoney(); break; case MENU_INSERT_DRINK: InsertDrink(); break; case MENU_ENDCODE: EndMachine(); break; } } else PrintErrorMessage (); } } int main() { vending_machine VendingMachine; VendingMachine.Run (); return 0; } }}} 이쯤에서 문제점 - vending_machine 이 완전히 God 클래스입니다. 완전히 이 프로그램 자체가 vending_machine 객체와 동급이 되어버리죠. 입출력부분과 Vending Machine 자체의 분리 {{{~cpp #ifndef _VENDINGMACHINE_H_ #define _VENDINGMACHINE_H_ #include #include #include #include #include using namespace std; class Drink { public: string name; int price; int amount; Drink (string name, int price, int amount) { this->name = name; this->price = price; this->amount = amount; } }; class VendingMachine { public: int money; vector drinks; vector validMoney; VendingMachine() { this->money = 0; string drinkNames[] = {"coke", "juice", "tea", "cofee", "milk"}; int price[] = {400, 600, 500, 450, 350}; int defaultAmount = 10; int TOTAL_DRINK_TYPE = 5; int validMoneyList[] = {10, 50, 100, 500, 1000}; int TOTAL_MONEY_TYPE = 5; Drink* drink; for (int drinkIndex=0; drinkIndex=0 && drinkIndex <5); } void chargeDrink (int drinkIndex, int amount) { drinks[drinkIndex]->amount += amount; } vector getValidMoneyTypes(void) { return this->validMoney; } bool VendingMachine::isBuyable(int drinkId) { return ((getMoney() - drinks[drinkId]->price >= 0) && (drinks[drinkId]->amount >= 1)); } vector getRegisteredDrinks () { return this->drinks; } void VendingMachine::buy (int drinkId) { drinks[drinkId]->amount--; chargeMoney (drinks[drinkId]->price); } void registerDrink (Drink* drink) { drinks.push_back(drink); } bool isValidMoneyType (int money) { for (int i=0; imoney; this->money = 0; return takeBackMoney; } void insertMoney (int money) { this->money += money; } void chargeMoney (int drinkPrice) { this->money -= drinkPrice; } int getMoney () { return money; } }; #endif main.cpp #include "VendingMachine.h" #include #include using namespace std; enum { MENU_ENDCODE = 0, MENU_START = 0, MENU_GET_MONEY, MENU_BUY, MENU_TAKEBACK_MONEY, MENU_INSERT_DRINK, MENU_END = MENU_INSERT_DRINK }; typedef void(*Func)(VendingMachine&); void InsertMoney(VendingMachine& vendingMachine); void Buy(VendingMachine& vendingMachine); void TakeBackMoneyMenu(VendingMachine& vendingMachine); void InsertDrink(VendingMachine& vendingMachine); void EndMachine(VendingMachine& vendingMachine); void PrintErrorMessage (); void PrintErrorInvalidCoinMessage (VendingMachine& vendingMachine); void PrintInsertCoinMenu(); void PrintCurrentMoney (int money); void PrintBuyMenu (int money); void PrintCurrentDrinkStatus (); void PrintErrorInvalidCoinMessage (VendingMachine& vendingMachine) { cout << "돈을 넣으세요. "; vector validMoney = vendingMachine.getValidMoneyTypes(); for (int i=0;i drinks = vendingMachine.getRegisteredDrinks(); for(int drinkIndex = 0 ; drinkIndex < drinks.size() ; drinkIndex++) { cout << drinkIndex << "." << drinks[drinkIndex]->name << "\t\t" << drinks[drinkIndex]->price << "\t" << drinks[drinkIndex]->amount << "\n"; } PrintCurrentMoney (vendingMachine.getMoney()); cout << "원하는 음료수를 선택하세요 : "; } void Buy(VendingMachine& vendingMachine) { PrintBuyMenu (vendingMachine); int drinkId; cin >> drinkId; if(vendingMachine.isBuyable(drinkId)) { vendingMachine.buy (drinkId); cout << vendingMachine.getMoney() << "원이 남았어요\n"; } else cout << "잔액이 부족하거나 수량이 부족해요\n"; } void TakeBackMoney (VendingMachine& vendingMachine) { int takeBackMoney = vendingMachine.takeBackMoney (); cout << "거스름돈" << takeBackMoney << "원을 돌려드립니다\n"; } void PrintCurrentDrinkStatus (VendingMachine& vendingMachine) { vector drinks = vendingMachine.getRegisteredDrinks(); for(int drinkIndex = 0 ; drinkIndex < drinks.size() ; drinkIndex++) cout << drinkIndex << "." << drinks[drinkIndex]->name << "\t" << drinks[drinkIndex]->amount << "\n"; } void PrintErrorMessage () { cout << "잘못된 메뉴 선택입니다. 메뉴를 다시 입력해주세요\n"; } void InsertMoney(VendingMachine& vendingMachine) { int money = 0; cout << "돈을 넣으세요. "; vector validMoney = vendingMachine.getValidMoneyTypes(); for (int i=0;i> money; if (vendingMachine.isValidMoneyType (money)) { vendingMachine.insertMoney (money); PrintCurrentMoney (vendingMachine.getMoney ()); } else PrintErrorInvalidCoinMessage (vendingMachine); } void InsertDrink(VendingMachine& vendingMachine) { int selectDrink; int insertAmount; PrintCurrentDrinkStatus (vendingMachine); cout << "채우길 원하는 음료수를 선택하세요 : "; cin >> selectDrink; cout << "채우길 원하는 음료수 수량을 입력해주세요 : "; cin >> insertAmount; if (vendingMachine.isValidDrinkIndex (selectDrink)) { vendingMachine.chargeDrink (selectDrink, insertAmount); cout << "음료수를 채웠습니다\n"; } PrintCurrentDrinkStatus (vendingMachine); } void EndMachine(VendingMachine& vendingMachine) { cout << "자판기를 종료합니다!!\n\n"; } bool isEndMenu (int choice) { return choice != MENU_ENDCODE; } bool isValidMenu (int choice) { return choice >= MENU_START && choice <= MENU_END; } int InputMainMenu () { int choice = -1; cout << "\n자판기 입니다\n" << "1.돈을 넣는다\n" << "2.물건을 산다\n" << "3.돈을 거슬러 받는다\n" << "4.음료수를 채운다\n" << "0.종료한다\n" << "메뉴를 선택하세요 : "; cin >> choice; return choice; } int main() { VendingMachine vendingMachine; int choice = -1; int menuList[] = { MENU_GET_MONEY, MENU_BUY, MENU_TAKEBACK_MONEY, MENU_INSERT_DRINK, MENU_ENDCODE}; Func funcList[] = { InsertMoney, Buy, TakeBackMoney, InsertDrink, EndMachine }; map menuTable; for (int menuIndex=0; menuIndex<5; menuIndex++) { menuTable[menuList[menuIndex]] = funcList[menuIndex]; } while (isEndMenu (choice)) { choice = InputMainMenu (); if (isValidMenu (choice)) { (*menuTable[choice])(vendingMachine); } else PrintErrorMessage (); } return 0; } }}}