Calculator设计文档.docx
- 文档编号:3230387
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:13
- 大小:166.66KB
Calculator设计文档.docx
《Calculator设计文档.docx》由会员分享,可在线阅读,更多相关《Calculator设计文档.docx(13页珍藏版)》请在冰点文库上搜索。
Calculator设计文档
一、整体设计
【View层】:
负责接收用户输入、将用户的输入序列传给controller层,然后等待controller返回要回显的东西(可以是正在输入的一串数字,也可以是中间结果)。
【Controller层】:
负责接收view传来的输入(字符序列),并根据序列特征进行解析(是否根据优先级计算某部分中间结果,是否是异常的不该回显的符号等),如果要计算中间结果就交给module层计算并等待其返回,最后将要回显的字符序列回传给view。
【Module层】:
负责接收来自controller的计算任务,进行各种一次运算(加、减、乘、除、单目运算等),将计算结果迅速返回给controller(如果是不可能的计算任务,比如div0,得返回特定的错误符号)。
用户输入
Module(专职计算)
Controller(解析序列)
View
接收输入的单个符号回传需要显示的东西
接收计算任务回传计算结果(必要时是错误符号)
二、接口设计
1、Controller
classCalculatorControl
{
public:
CalculatorControl(ICalculatorModel*pCalculatorModel);
~CalculatorControl(void);
//接收用户指令
stringReceiveCommand(COMMANDstCommand);
//设置计算器的模式
voidSetCalculatorForm(CALCULATOR_FORMemStatus);
//获取计算器的模式
CALCULATOR_FORMGetCalculatorForm(void);
//获取用于View显示的数据
stringGetStringToDisplay(void);
protected:
//初始化
voidInitControl();
//获取数字按键对应的string
stringGetOperatorNumber(OPERATOR_SETemOperator);
//获取操作符的优先级
intGetOperatorPriority(OPERATOR_SETemOperator);
//处理不同的指令
voidDisposeCommand(COMMANDstCommand);
//检测操作符栈中是否存在指定符号
boolCheckOperatorInStack(OPERATOR_SETemOperator);
CALC_RESULT_STATUSDoBinOperate(string&strErrMsg);
CALC_RESULT_STATUSDoUnaryOperate(string&strErrMsg);
voidPushToOperatorStack(OPERATOR_SETemOperator);
voidPushToOperandStack(stringstrOperand);
CALC_RESULT_STATUSProcBinOperator(OPERATOR_SETemBinOp);
CALC_RESULT_STATUSProcUnrayOperator(OPERATOR_SETemUnrayOp);
voidProcLeftBracket(void);
CALC_RESULT_STATUSProcRightBracket(void);
private:
//操作数栈
vector
//操作符栈
vector
//记录上次操作:
,操作数栈;,操作符栈;,尚未入栈的操作数
CONTROL_STATUSm_emControlStatus;
//记录最后一次运算的右操作数
stringm_strLastRightOperand;
//记录最后一次运算的操作符
OPERATOR_SETm_emLastOperator;
//尚未入栈的操作数
stringm_strInputOperand;
//尚未入栈操作数的状态
INPUT_STATUSm_emInputStatus;
//计算器的模式:
,标准模式;,科学模式
CALCULATOR_FORMm_emCalculatorStatus;
//数字按键与string对照表
OperatorNumberMapm_mapOperatorNumberMap;
//用于View显示的数据
stringStringToDisplay;
//底层运算接口
ICalculatorModel*m_pCalculatorModel;
};
2、Model
接收计算任务并回传计算结果
enumCALC_RESULT_STATUS
{
CALC_RESULT_NORMAL=0,
CALC_RESULT_ERROR,
CALC_RESULT_UNUSUAL
};
classICalculatorModel
{
public:
virtualCALC_RESULT_STATUSCalculateData(conststring&lhs,conststring&rhs,OPERATOR_SETemOperator,string&CalcResult)=0;
};
#ifdef_UNIT_TEST
classSimpleCalculatorModel:
publicICalculatorModel
{
public:
virtualCALC_RESULT_STATUSCalculateData(conststring&lhs,conststring&rhs,OPERATOR_SETemOperator,string&CalcResult);
};
#endif//_UNIT_TEST
classCalculatorModel:
publicICalculatorModel
{
public:
CalculatorModel(void);
~CalculatorModel(void);
virtualCALC_RESULT_STATUSCalculateData(conststring&lhs,conststring&rhs,OPERATOR_SETemOperator,string&CalcResult);
};
三、实现细节
1、View
用户每点击一个按钮,就将该按钮对应的ID(在EMUN_OP_SET枚举类型中集体定义)传递给Controller:
:
ReceiveChar(ID),并等待该回显的结果。
以输入序列为“1+2*3+”为例:
输入1,传给controller,controller返回1;输入+,传给controller,controller返回1;输入2,controller返回2;输入*,controller返回2;输入3,controller返回3;输入+,controller返回一个中间结果7。
2、Controller
通过双栈(数字栈和运算符栈),进行解析输入序列,并灵活应各种怪异的序列。
双栈原理:
如果接收到一个运算符,先与运算符栈中的栈顶运算符进行比较,如果当前运算符的优先级<=栈顶运算符优先级,就从数字栈中弹出两数字进行运算(交给Module计算),而且所有该算的都应该算完(比如:
已经输入1+2*3,当输入+时,应该把2*3=6计算之后接着计算1+6=7)。
四、如何应对怪异序列
用户不停的逐个点击按钮,controller源源不断的接收符号,当前待接收的符号和controller的状态决定了下一步该做哪一系列的处理,并且针对该符号的这一系列处理结束后会赋予controller一个新的状态,以迎接下一个即将到来的符号。
总的来说就是——哪类符号面临哪种状态会做出一系列套路般的处理,处理完后会赋予一种新的状态。
(1)Controller的状态可以分为三种:
1、STATUS_OPERAND:
表示计算器刚刚启动或上次有了一个中间结果。
2、STATUS_OPERATOR:
表示上次输入了一个运算符(单目、双目、括号)
3、STATUS_TEMPSTRING:
表示上一次输入的是数字或者小数点。
(2)各种符号可以分为六类,下面举一些异常的例子加以明:
1、单目运算符:
永远不会进运算符栈,会及时计算出来——输入“5+cos”,那么会变成“5+cos5”,也就是说单目是待接收的符号并且上次是STATUS_OPERATOR(运算符状态),那么该单目符号会把栈顶的数字当做操作数进行计算并将中间结果压入数字栈。
再如——输入“5(cos”,会变成“(cos5”。
2、左括号
待接收符号是‘(’时,得在逻辑上保证:
A、左括号前不可能紧邻数字;
B、左括号后不可能紧邻运算符。
针对A,如果当前状态为STATUS_OPERAND(上次输入了一个数字),那么左括号进运算符栈并将状态保持为STATUS_OPERAND,就在逻辑上将上次的数字放在括号内了——输入“5(”就变成“(5”;针对B,如果当前状态是STATUS_OPERATOR(上一次输入的是运算符),那么左括号进运算符栈并在数字栈中压入0,将状态保持为STATUS_OPERAND,就在逻辑上保证了左括号后始终有个数字存在——输入“(+”变成“(0+”。
3、右括号
待接收符号是‘)’时,得在逻辑上保证:
A、前面必须有能匹配的左括号;
B、右括号前不可能紧邻运算符
针对A,如果运算符栈中不存在左括号,那么就忽略右括号的输入(因为右括号遇到左括号会计算他们中间的局部结果并消掉括号,运算符栈中最多只可能存在一个左括号);针对B,如果当前状态时STATUS_OPERATOR,那么就复制一份数字栈顶元素,——输入“(8*)”变成“(8*8)”。
4、双目运算符
待接收符号是双目时,得保证:
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,那么再输入数字就覆盖数字栈顶元素
五、各类符号所对应的套路般处理流程
接收输入序列后的解析流程如下:
<1>双目运算符
<2>单目运算符
<3>等号运算符
<4>输入数字
<5>左括号
<6>右括号
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Calculator 设计 文档