Tokens Operations
Description:
Reverse Polished Calculator OO design
Example:
Note
Idea:
先把calculator设计成factory pattern,然后在Tokens类里基本相当于读取,Calculator类相当于处理。
每个operator还可以specify自己的number of operands。
Code:
#include <iostream>
#include <vector>
#include <unordered_map>
#include <climits>
#include <cassert>
#include <stack>
#include <cstdlib>
#include <exception>
#include <stdexcept>
using namespace std;
class Operation{
public:
virtual ~Operation(){}
virtual int getResult(const vector<int>& nums)=0;
int operand_num;
};
class Add: public Operation{
public:
Add();
int getResult(const vector<int>& nums) override{
int result=0;
for(auto& e: nums){
result += e;
}
return result;
}
};
class Sub: public Operation{
public:
Sub();
int getResult(const vector<int>& nums) override{
int result=nums[0] + nums[0];
for(auto& e: nums){
result -= e;
}
return result;
}
};
class Mul: public Operation{
public:
Mul();
int getResult(const vector<int>& nums) override{
int result=1;
for(auto& e: nums){
result *= e;
}
return result;
}
};
class Div: public Operation{
public:
Div();
int getResult(const vector<int>& nums) override{
int result=nums[0];
for(int i=1; i<operand_num; i++){
if(nums[i]==0) throw runtime_error("divide by zero");
result /= nums[i];
}
return result;
}
};
class OperationFactory{
public:
Operation * newOperation(char operation_name){
if(operation_dict_.find(operation_name)==operation_dict_.end()) return nullptr;
return operation_dict_[operation_name];
}
void setOperationDict(char operation_name, Operation& operation_obj){
operation_dict_[operation_name] = &operation_obj;
}
static OperationFactory * getInstance(){
if(instance_ptr_==nullptr){
instance_ptr_ = new OperationFactory;
}
return instance_ptr_;
}
private:
unordered_map<char, Operation *> operation_dict_;
static OperationFactory * instance_ptr_;
};
OperationFactory * OperationFactory::instance_ptr_=nullptr;
Add add_obj;
Add::Add(){
operand_num=2;
OperationFactory::getInstance()->setOperationDict('+', add_obj);
}
Sub sub_obj;
Sub::Sub(){
operand_num=2;
OperationFactory::getInstance()->setOperationDict('-', sub_obj);
}
Mul mul_obj;
Mul::Mul(){
operand_num=2;
OperationFactory::getInstance()->setOperationDict('*', mul_obj);
}
Div div_obj;
Div::Div(){
operand_num=2;
OperationFactory::getInstance()->setOperationDict('/', div_obj);
}
class Tokens{
public:
Tokens(const vector<string> & input): s(input), index(0) {}
bool hasNext(){
return index<s.size();
}
bool isValue(){
if(s[index].size()==1) return isdigit(s[index][0]);
// In case number is -10
else return isdigit(s[index][1]);
}
char getOperator(){
return s[index++][0];
}
int getOperand(){
return atoi(s[index++].c_str());
}
private:
vector<string> s;
int index;
};
class Calculator{
public:
Calculator(const vector<string> & input): tk(new Tokens(input)) {}
~Calculator() { delete tk; }
int eval(){
while(tk->hasNext()){
if(tk->isValue()){
stack_c.push(tk->getOperand());
}
else{
op = OperationFactory::getInstance()->newOperation(tk->getOperator());
int op_num = op->operand_num;
vector<int> nums(op_num);
for(int i=0; i<op_num; ++i){
if(!stack_c.empty()){
nums[op_num-1-i]=stack_c.top();
stack_c.pop();
}
}
stack_c.push(op->getResult(nums));
}
}
if(!stack_c.empty()) return stack_c.top();
return 0;
}
private:
stack<int> stack_c;
Tokens * tk;
Operation * op;
};
int main(){
vector<string> tokens = {"4", "13", "5", "/", "+"};
Calculator my_cal(tokens);
cout<<my_cal.eval()<<endl;
}