E N D
Pocket Calculator Simulation An object-based program is more interesting when multiple objects are involved. In addition to acting as peers or agents, objects can also serve as components in other objects, and building a class with component objects can enhance encapsulation, flexibility, and modifiability. A pocket calculator simulation program is used to illustrate this points.
Pocket Calculator Simulation • Program design Applying object-based programming for our simulation, we employ object found in an actual calculator: • A manager object (Calculator) that employs a compute engine component and a user interface component to perform the simulation. • A user interface object (CalcFace) that reports user input to the Calculator and display results. • A compute object( CalcEng) that supplies computing abilities and stores data.
Pocket Calculator Simulation • The CalcEng class The calculator engine object performs the compute-methods: • The method setOperand(设置运算数) is used to enter numeric data into the compute engine ( 23 + 32). • The method operate is called to enter the next opcode and triger engine operations(当具有两个操作数时,触发计算功能,call compute). • The method getOpcode is called to obtain the internally kept operator code(+, - ,* so on). • The method getOutput is invoked to produce the argument currently stored.
Pocket Calculator Simulation The calculator compute engine works with three fundamental quantities: • The field ans is the answer, or result of requested computations, initialized to 0.0. • The field op is the operation code (or opcode), one of the characters in the constant KEYS string, whose left operand is always ans. • The field arg is the right operand of op. • The field argcnt is used to store the number of operand.
Pocket Calculator Simulation 开始 ans=ans op args ans=9.8; args=0.0; op=‘=‘; argcnt=1 ans=9.8; args=0.0; op=‘+‘; argcnt=1 ans=9.8; args=1.2; op=‘+‘; argcnt=2 Argcnt=2 开始计算 结果存入ans,argcnt=1 ans = arg = 0.0; argcnt = 1; op = '='; ans=11; args=1.2; op=‘/‘; argcnt=1 ans=11; args=2; op=‘/‘; argcnt=2 ans=5.5; args=2; op=‘=‘; argcnt=1 setOperand operate getOutput cal.setOperand(9.8); cal.setOperate(‘=’); cal. operate(‘+’); 结束 cal.setOperand(1.2); cal. operate(‘/’); cal.setOperand(2);
Pocket Calculator Simulation /////// CalcEng.java /////// class CalcEng { // public members public CalcEng() { allClear(); } public String keys() { return KEYS; } public byte precision() { return PREC; } public char getOpcode() { // returns current opcode return op; } // 如果有两个操作时,表示表达式还没计算,返回右操作数, public double getOutput(){ // returns current argument return( argcnt==2 ? arg : ans ); } 读取计算器支持的操符: "+-*/=NAC” 读取计算器支持的数据精度:8
Pocket Calculator Simulation public void operate(char nc) { // nc is next opcode switch( nc ){ case 'A': allClear(); return; // All Clear case 'C': clear(); return; // Clear case 'N': // sign change if ( argcnt == 1 ) ans = -ans; else arg = -arg; return; default : // +-*/= compute(); op = nc; // new opcode } }
Pocket Calculator Simulation /// private members private void compute(){ if ( argcnt == 2 ){ switch( op ){ case '+': ans += arg; break; case '-': ans -= arg; break; case '*': ans *= arg; break; case '/': ans /= arg; break; } argcnt = 1; } }
Pocket Calculator Simulation 清计算器时,若此时只一个操作数,则彻底清空 private void clear(){ if ( argcnt == 1 ) { ans = 0.0; op = '='; }else{ arg = 0.0; argcnt = 1; } } public void setOperand(double in) { if ( op == '=' ) ans = in; else{ arg = in; argcnt = 2; } } 否则,只清右操作数,并计此时只一个操作数 如果操作符目前为=,则计算结果直接为in 否则,将输入值赋给右操作数,并计录此时 已有两个操作数了.
Pocket Calculator Simulation • //为了调式方便,而增加的,实际使用时可使删除 • public static void main(String[] args){ • CalcEng cal = new CalcEng(); • cal.setOperand(9.8); • cal.operate('+'); • cal.setOperand(1.2); • cal.operate('/'); • cal.setOperand(2.0); • cal.operate('='); • System.out.println(cal.getOutput()); • } private void allClear(){ ans = arg = 0.0; argcnt = 1; op = '='; } private final String KEYS = "+-*/=NAC"; private final byte PREC = 8; //digit number private double ans, arg; private char op; // operation code private int argcnt; // argument count }
Pocket Calculator Simulation /////// CalcFace.java /////// import java.io.*; class CalcFace { public CalcFace(String k, byte pr){ keys = k; //记录支持的op prec = pr++; //记录支持的精度 nbuf = new StringBuffer(prec); //缓冲区 reset(); } public void setCalc(Calculator ca){ calc = ca; } public void showNumber(String s) { System.out.println(prompt + s); } public void showOp(char op) { //暂为空 } CalcFace have three public interface setCalc: used by Calculator Intput: used by Calculator showNumber; used by Calculator showOp; 该对象的作用是负责读取输入的字符, 并将结果返回给Calculator
private String prompt="Calc: "; • private Calculator calc; • private String keys; // keys recognized • private StringBuffer nbuf; // buffer for input number • private boolean num = false Pocket Calculator Simulation Tthe input method runs in a continuous loop, entering each input character, until the standard input is closed(即输入Ctrl-z退出计算) public void input() throws IOException { int i; while ( (i= inchar()) != -1 ){ enter((char) i); } } private void enter(char c) { if ( keys.indexOf(c) != -1 ){ // if c an operator showOp(c); if ( num ) calc.enterNumber(extractNumber(), c); else calc.enterOp(c); reset(); }else if ( nump(c) && nbuf.length() < prec ) { num = true; buildNumber(c); //精度为prec位的数 } } The enter method processes each input character. If the Character is not an opcode, it is treated as part of an Input number. • private int inchar() • throws IOException • { • return System.in.read(); • } 如果当前为operator, 若num=true(即前面为数字), 则从buffer中提取数字.否则输入opcode 如果当前不为operator,则看是否超过充许精度. 若超过丢弃超过部分.
Pocket Calculator Simulation private boolean nump(char c){ return( c == '.' || Character.isDigit(c) ); } private String extractNumber() { return (nbuf.length() == 0) ? “0”: nbuf.toString(); //将StringBuffer转换成String对象 } private void buildNumber(char c){ int i = nbuf.length(); if ( i == 0 && c == '0') return; // ignore leading zeros if ( c == '.' ) { // at most one decimal point if ( ! before_point ) return; else before_point = false; } nbuf.append(c); }
Pocket Calculator Simulation private void reset(){ before_point = true; nbuf.setLength(0); num = false; } private int inchar() throws IOException { return System.in.read(); } private String prompt="Calc: "; private Calculator calc; private String keys; // keys recognized private StringBuffer nbuf; // buffer for input number private byte prec; // max no of chars displayable private boolean before_point = true; private boolean num = false; }
Pocket Calculator Simulation /////// Calculator.java /////// public class Calculator { public Calculator(CalcEng e, CalcFace f){ eng = e; cf = f; f.setCalc(this); } public void on() throws java.io.IOException { output(); cf.input(); } public void enterNumber(String number, char op){ eng.setOperand( Double.parseDouble(number) ); enterOp(op); } • private void output(){ • double number = eng.getOutput(); • cf.showNumber(""+number); • } 进入CalcFace Object的input方法后, 即进入一个死循环 被CalcFace对象调用
Pocket Calculator Simulation 被CalcFace对象调用 public void enterOp( char op ){ eng.operate( op ); output(); } private void output(){ double number = eng.getOutput(); cf.showNumber(""+number); } private CalcEng eng = null; private CalcFace cf = null; } 输入opcode时,若附合条件:argcn=2,则进行计算
Pocket Calculator Simulation /////// RunCalc.java /////// public class RunCalc { public static void main(String[] args) throws java.io.IOException { CalcEng e = new CalcEng(); CalcFace f = new CalcFace(e.keys(), e.precision()); Calculator x = new Calculator(e, f); x.on(); return; } } • public void on() • throws java.io.IOException • { • output(); • cf.input(); • } 启动Calculator