Toggle menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

SuperMarket/인수

From ZeroWiki
Revision as of 05:28, 7 February 2021 by imported>Unknown
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
// 캬오옷.. 졸라 심심하다 ㅠ.ㅠ 학교 와서 노닥거리다가 걍 해봤음. 파서 만드는데 80프로 이상의 시간을..--;
// 대강의 예외처리도 된거 같고.. 고칠거 있음 말해주길
// DeleteMe 헉 이 미완의 컬러링 비밀 기능을 .. 어떻게 알고.. 

// 문제의 코드 부분
// 아래로 이어지는 if/else-if는 코드 중복이라고 봅니다. 이걸 어떻게 제거할 수 있을까요? Command Pattern? Polymorphism? 혹은 그냥 Table Lookup? --JuNe

		if(command == "help")
		{
			Helper::showCommand();			
		}
		else if(command == "mymoney")
		{
			cout << sm.getRestMoney() << endl;
		}
		else if(command == "inventory")
		{
			user.showBuyedGoods();
		}
		else if(command == "ask")
		{
			string good(&str[token+1], &str[str.size()]);
			sm.answerCost(good);
		}
		else if(command == "deposit")
		{
			string m(&str[token+1], &str[str.size()]);
			int money = StringConvertToInt(m);
			user.depositMoney(sm, money);
		}
		else if(command == "exit")
		{
			exit(0);
		}
		else if(command == "menu")
		{
			sm.showMenu();
		}
		else if(command == "buy")
		{
			int token2 = getToken(str,2);
			string good(&str[token+1], &str[token2]);
			
			string cnt(&str[token2+1], &str[str.size()]);
			int count = StringConvertToInt(cnt);
			
			user.buyGoods(sm, sm.findGoods(good), count);
		}
		else if(command == "cancel")
		{
			int token2 = getToken(str,2);
			string good(&str[token+1], &str[token2]);
			
			string cnt(&str[token2+1], &str[str.size()]);
			int count = StringConvertToInt(cnt);
			
			user.cancleGoods(sm, sm.findGoods(good), count);
		}

// 어떻게 하면 if/else if 중복을 없앨수 있을까 고민하다가 폴리모피즘을 이용하기로 했습니다.(근데 이거 폴리모피즘이 맞나?--;) 
// map<string, Cmd*> 이런식으로 string에는 커맨드를,Cmd 클래스는 HelpCmd클래스, Deposit클래스 등등의 부모 클래스, 즉 명령 클래스들의 
// 조상 클래스를 포인터로 넣어줬습니다. 동적 바인딩을 하기 위해서..--; Parser생성할때 map 테이블에다 명령들을 넣어주면서 그 명령에 
// 해당하는 클래스를 동적 할당해주면서 넣었습니다. 소멸자에서는 해제하는 것도 잊지 않았구요. 나름대로 상당히 고민을 했지만..--; 
// 이것밖엔 답이 안나오네요.



// 그래서 나름대로 고쳐본 것

#include <iostream>
#include <string>
#include <vector>
#include <cassert>
#include <map>
using namespace std;

class SuperMarket;
class User;
class Parser;
class Helper;
class Goods;
class Packages;
class Cmd;

class Goods
{
private :
	string _name;
	int _cost;
public :
	Goods(const string& name, int cost) : _name(name), _cost(cost) {}

	const string& getName() const
	{
		return _name;
	}
	int getCost() const
	{
		return _cost;
	}
};

class Packages
{
private :
	Goods _good;
	int _count;
public :
	Packages(const Goods& good, int count) : _good(good), _count(count) {}
	
	const Goods& getGoods() const
	{
		return _good;
	}

	int getCount() const
	{
		return _count;
	}

	void setCount(int n)
	{
		_count = n;
	}
};

class SuperMarket
{
private :
	int _receivedMoney;
	vector<Goods> _havingGoods;
public :
	SuperMarket()
	{
		Goods g1("candy",1000);
		_havingGoods.push_back(g1);
		Goods g2("diskette",1200);
		_havingGoods.push_back(g2);
		Goods g3("mouse",5000);
		_havingGoods.push_back(g3);
		_receivedMoney = 0;
	}
	void receiveMoney(int money)
	{
		_receivedMoney = money;
		cout << "OK" << endl;
	}
	void showMenu() const
	{
		cout << " 메뉴 " << endl;
		for(int i = 0 ; i < _havingGoods.size() ; ++i)
		{
			cout << _havingGoods[i].getName() << " " << _havingGoods[i].getCost() << endl;
		}
	}
	void sellGoods(const Goods& goods, int count) 
	{
		_receivedMoney -= goods.getCost() * count;
	}
	int getRestMoney() const
	{
		return _receivedMoney;
	}
	const vector<Goods>& getGoods() const
	{
		return _havingGoods;
	}
	void answerCost(const string& goodsName) const
	{
		bool isFind = false;
		for(int i = 0 ; i < _havingGoods.size() ; ++i)
		{
			if(_havingGoods[i].getName() == goodsName)
			{
				cout << _havingGoods[i].getCost() << endl;
				isFind = true;
				break;
			}
		}		
		if(!isFind)
		{
			cout << "그런 물건 없음!" << endl;
		}
	}

	const Goods& findGoods(const string& goodsName) const
	{
		for(int i = 0 ; i < _havingGoods.size() ; ++i)
		{
			if(_havingGoods[i].getName() == goodsName)
			{
				return _havingGoods[i];
			}
		}				
	}
};

class User
{
private :
	vector<Packages> _buyedGoods;
public :
	void depositMoney(SuperMarket& sm, int money) const
	{
		sm.receiveMoney(money);
	}
	void showBuyedGoods()
	{
		if(_buyedGoods.size() == 0)
			cout << "None" << endl;
		else
		{
			for(int i = 0 ; i < _buyedGoods.size() ; ++i)
			{
				cout << _buyedGoods[i].getGoods().getName() << " " << _buyedGoods[i].getCount() << endl;
			}
		}
	}
	void buyGoods(SuperMarket& sm, const Goods& goods, int count)
	{
		if(sm.getRestMoney() < goods.getCost() * count)
			cout << "can't buy" << endl;
		else
		{
			sm.sellGoods(goods, count);
			Packages p(goods, count);
			_buyedGoods.push_back(p);
		}
	}
	void cancleGoods(SuperMarket& sm, const Goods& goods, int count)
	{
		bool isFind = false;		
		int nth = 0;
		for(int i = 0 ; i < _buyedGoods.size() ; ++i)
		{
			if(goods.getName() == _buyedGoods[i].getGoods().getName())
			{
				isFind = true;
				nth = i;
			}
		}
		if(!isFind)
			cout << "그 물건 안샀어요." << endl;
		else
		{
			if(_buyedGoods[nth].getCount() < count)
			{
				cout << "산 것보다 더 많이 취소 못합니다." << endl;
			}
			else if(_buyedGoods[nth].getCount() == count)
			{
				if(_buyedGoods[nth].getCount() == 0)
				{
					_buyedGoods.erase(_buyedGoods.begin() + nth);
				}
			}
			else
			{
				_buyedGoods[nth].setCount( _buyedGoods[nth].getCount() - count );
			}
		}
	}
};

class Helper
{
public :
	static void showCommand()
	{
		cout << "* deposit <money> -- 돈을 money만큼 예금한다. " << endl;
		cout << "* mymoney -- 남은 돈을 보여준다." << endl;
		cout << "* buy <product> <count> -- product 물건을 count 만큼 산다." << endl;
		cout << "* inventory -- 산 물건의 목록을 보여준다 ." << endl;
		cout << "* cancel <product> <count> -- 산 product 물건을 count개만큼 취소한다 ." << endl;
		cout << "* ask <product> -- procuct 물건의 가격을 묻는다 ." << endl;
		cout << "* menu -- 구매 가능한 물건의 목록을 보여준다 ." << endl;
		cout << "* exit -- 가게를 나간다 ." << endl;
	}
};

class Cmd
{
public :
	virtual void executeCommand(SuperMarket& sm, User& user, const string& str) = 0;
	static int getToken(const string& str, int nth) 
	{
		int ret = str.size();
		int count = 0;
		for(int i = 0 ; i < str.size() ; ++i)
		{
			if(str[i] == ' ')
			{
				ret = i;
				++count;
				if(count == nth)
					return ret;
			}
		}
		return ret;
	}
	int StringConvertToInt(string& str) 
	{ 
		int ret = 0; 
		for(int i = 0 ; i < str.length() ; ++i) 
		{ 
			ret += CharToInt(str[i]) * Power(10,(str.length() - i)); 
		} 
		return ret; 
	} 
 
	int CharToInt(char ch) 
	{ 
		return ch - 48; 
	} 
 
	int Power(int c, int e) 
	{ 
		int ret = 1; 
		for(int i = 0 ; i < e - 1 ; ++i) 
		{ 
			ret *= c; 
		} 
		return ret; 
	} 
};

class HelpCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		Helper::showCommand();
	}
};

class MyMoneyCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		cout << sm.getRestMoney() << endl;				
	}
};

class InventoryCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		user.showBuyedGoods();
	}
};

class AskCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		int token = getToken(str, 1);
		string good(&str[token+1], &str[str.size()]);
		sm.answerCost(good);		
	}
};

class DepositCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		int token = getToken(str, 1);
		string m(&str[token+1], &str[str.size()]);
		int money = StringConvertToInt(m);
		user.depositMoney(sm, money);		
	}
};

class ExitCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		exit(0);	
	}
};

class MenuCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		sm.showMenu();
	}
};

class BuyCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		int token = getToken(str,1);
		int token2 = getToken(str,2);
		string good(&str[token+1], &str[token2]);
		
		string cnt(&str[token2+1], &str[str.size()]);
		int count = StringConvertToInt(cnt);
		
		user.buyGoods(sm, sm.findGoods(good), count);
	}
};

class CancleCmd : public Cmd
{
public :
	void executeCommand(SuperMarket& sm, User& user, const string& str)
	{
		int token = getToken(str,1);
		int token2 = getToken(str,2);
		string good(&str[token+1], &str[token2]);
		
		string cnt(&str[token2+1], &str[str.size()]);
		int count = StringConvertToInt(cnt);
		
		user.cancleGoods(sm, sm.findGoods(good), count);	
	}
};

class Parser
{
private :
	map<string, Cmd*> _tableCmd;
public :
	Parser()
	{
		_tableCmd["help"] = new HelpCmd();
		_tableCmd["mymoney"] = new MyMoneyCmd();
		_tableCmd["inventory"] = new InventoryCmd();
		_tableCmd["ask"] = new AskCmd();
		_tableCmd["deposit"] = new DepositCmd();
		_tableCmd["exit"] = new ExitCmd();
		_tableCmd["menu"] = new MenuCmd();
		_tableCmd["buy"] = new BuyCmd();
		_tableCmd["cancle"] = new CancleCmd();
	}
	void translateCommand(SuperMarket& sm, User& user, const string& str) 
	{
		int token = Cmd::getToken(str,1);
		string command(&str[0], &str[token]);

		_tableCmd[command]->executeCommand(sm, user, str);		
	}
	
	virtual ~Parser()
	{
		map<string, Cmd*> :: iterator i;
		for(i = _tableCmd.begin() ; i != _tableCmd.end() ; ++i)
		{
			delete &(i->second);
		}
	}
};

int main()
{
	User user;
	SuperMarket superMarket;
	Parser parser;

	char command[30];
	
	while(1)
	{
		cout << endl << ">>> " ;
		cin.getline(command, 30);		

		parser.translateCommand(superMarket, user, command);
	}
	return 0;

}