1、class CalculatorControlpublic: CalculatorControl(ICalculatorModel *pCalculatorModel); CalculatorControl(void); /接收用户指令 string ReceiveCommand(COMMAND stCommand); /设置计算器的模式 void SetCalculatorForm(CALCULATOR_FORM emStatus);/获取计算器的模式 CALCULATOR_FORM GetCalculatorForm(void);/获取用于View显示的数据 string GetStrin
2、gToDisplay(void);protected:/初始化 void InitControl();/获取数字按键对应的string string GetOperatorNumber(OPERATOR_SET emOperator);/获取操作符的优先级 int GetOperatorPriority(OPERATOR_SET emOperator); /处理不同的指令void DisposeCommand(COMMAND stCommand);/检测操作符栈中是否存在指定符号 bool CheckOperatorInStack(OPERATOR_SET emOperator); CALC_
3、RESULT_STATUS DoBinOperate(string &strErrMsg); CALC_RESULT_STATUS DoUnaryOperate(string & void PushToOperatorStack(OPERATOR_SET emOperator); void PushToOperandStack(string strOperand); CALC_RESULT_STATUS ProcBinOperator(OPERATOR_SET emBinOp); CALC_RESULT_STATUS ProcUnrayOperator(OPERATOR_SET emUnray
4、Op); void ProcLeftBracket(void); CALC_RESULT_STATUS ProcRightBracket(void);private:/操作数栈 vector m_vectorOperandStack;/操作符栈OPERATOR_SET m_vectorOperatorStack;/记录上次操作:,操作数栈;,操作符栈;,尚未入栈的操作数 CONTROL_STATUS m_emControlStatus;/记录最后一次运算的右操作数 string m_strLastRightOperand;/记录最后一次运算的操作符 OPERATOR_SET m_emLastO
5、perator; /尚未入栈的操作数 string m_strInputOperand;/尚未入栈操作数的状态 INPUT_STATUS m_emInputStatus;/计算器的模式:,标准模式;,科学模式 CALCULATOR_FORM m_emCalculatorStatus;/数字按键与string对照表 OperatorNumberMap m_mapOperatorNumberMap;/用于View显示的数据 string StringToDisplay;/底层运算接口 ICalculatorModel *m_pCalculatorModel;2、Model接收计算任务并回传计算结果
6、enum CALC_RESULT_STATUS CALC_RESULT_NORMAL = 0, CALC_RESULT_ERROR, CALC_RESULT_UNUSUALclass ICalculatorModel virtual CALC_RESULT_STATUS CalculateData(const string &lhs, const string &rhs, OPERATOR_SET emOperator, string &CalcResult) = 0;#ifdef _UNIT_TESTclass SimpleCalculatorModel : public ICalculat
7、orModelCalcResult);#endif / _UNIT_TESTclass CalculatorModel : CalculatorModel(void); CalculatorModel(void);三、实现细节1、View 用户每点击一个按钮,就将该按钮对应的ID(在EMUN_OP_SET枚举类型中集体定义)传递给Controller:ReceiveChar(ID),并等待该回显的结果。以输入序列为“1+2*3+”为例:输入1,传给controller,controller返回1;输入+,传给controller,controller返回1;输入2,controller返回2;
8、输入*,controller返回2;输入3,controller返回3;输入+,controller返回一个中间结果7。2、Controller通过双栈(数字栈和运算符栈),进行解析输入序列,并灵活应各种怪异的序列。双栈原理:如果接收到一个运算符,先与运算符栈中的栈顶运算符进行比较,如果当前运算符的优先级=栈顶运算符优先级,就从数字栈中弹出两数字进行运算(交给Module计算),而且所有该算的都应该算完(比如:已经输入1+2*3,当输入+时,应该把2*3=6计算之后接着计算1+6=7)。四、如何应对怪异序列用户不停的逐个点击按钮,controller源源不断的接收符号,当前待接收的符号和con
9、troller的状态决定了下一步该做哪一系列的处理,并且针对该符号的这一系列处理结束后会赋予controller一个新的状态,以迎接下一个即将到来的符号。总的来说就是哪类符号面临哪种状态会做出一系列套路般的处理,处理完后会赋予一种新的状态。(1) Controller的状态可以分为三种:1、 STATUS_OPERAND:表示计算器刚刚启动或上次有了一个中间结果。2、 STATUS_OPERATOR:表示上次输入了一个运算符(单目、双目、括号)3、 STATUS_TEMPSTRING:表示上一次输入的是数字或者小数点。(2) 各种符号可以分为六类,下面举一些异常的例子加以明:1、 单目运算符:
10、永远不会进运算符栈,会及时计算出来输入“5+cos”,那么会变成“5+cos5”,也就是说单目是待接收的符号并且上次是STATUS_OPERATOR(运算符状态),那么该单目符号会把栈顶的数字当做操作数进行计算并将中间结果压入数字栈。再如输入“5(cos”,会变成“(cos5”。2、 左括号待接收符号是(时,得在逻辑上保证:A、左括号前不可能紧邻数字;B、左括号后不可能紧邻运算符。针对A,如果当前状态为STATUS_OPERAND(上次输入了一个数字),那么左括号进运算符栈并将状态保持为STATUS_ OPERAND,就在逻辑上将上次的数字放在括号内了输入“5(”就变成“(5”;针对B,如果当
11、前状态是STATUS_OPERATOR(上一次输入的是运算符),那么左括号进运算符栈并在数字栈中压入0,将状态保持为STATUS_ OPERAND,就在逻辑上保证了左括号后始终有个数字存在输入“(+”变成“(0+”。3、 右括号待接收符号是)时,得在逻辑上保证:A、前面必须有能匹配的左括号;B、右括号前不可能紧邻运算符针对A,如果运算符栈中不存在左括号,那么就忽略右括号的输入(因为右括号遇到左括号会计算他们中间的局部结果并消掉括号,运算符栈中最多只可能存在一个左括号);针对B,如果当前状态时STATUS_OPERATOR,那么就复制一份数字栈顶元素,输入“(8*)”变成“(8*8)”。4、 双
12、目运算符待接收符号是双目时,得保证:A、不可能存在相邻的多个双目运算符B、前面该算的局部表达式都应该得到计算 针对A,如果当前状态是STATUS_OPERATOR(上次输入了运算符),那么就用待接收的双目覆盖运算符栈顶的元素输入“5+*”变成“5*”;针对B,就得将待接收的双目符号优先级与运算符栈顶的进行比较,将前面能算的都算完输入“2+3*3+”,此时在逻辑上会变成“11+”。5、 等号待接收符号是“=”时,得一口气将前面所有的表达式算完。另外还有两种特殊情况:A、 运算符栈为空B、 =前面紧邻的是双目运算符针对A,如果LastOperator为空,表明之前没有进行任何运算,忽略,否则将LastOperator压入运算符栈且LastOperand压入数字栈,然后调用双目计算函数;针对B,以“5+=”为例,会变成“5+5=”且记录LastOperand=5、LastOperator=+,如果接着再输入=,那么就跳回针对A的处理流程。6、数符(数字或小数点) 待接收符号是数符时,得注意两点:A、一个数字不可能存在多个小数点B、如果当前状态为STATUS_OPERAND,那么再输入数字就覆盖数字栈顶元素五、各类符号所对应的套路般处理流程接收输入序列后的解析流程如下:双目运算符2单目运算符3等号运算符4输入数字5 左括号6 右括号
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2