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;
}

results matching ""

    No results matching ""