BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #16703同步于 2010/12/5
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

不怕脑残的进来

wks
2010/12/5镜像同步5 回复
这是一个RPN计算器。输入“1 2 + 3 *”,得到9. 每个组件传入参数,返回结果。但是main函数麻烦。 package rpn.returning; import java.util.*; import java.io.*; class Reader { public String read(InputStream is) throws IOException { Scanner s = new Scanner(is); return s.nextLine(); } } class Lexer { public String[] lex(String expression) { return expression.split(" +"); } } class Evaluator { public int eval(String[] tokens) { Stack<Integer> stack = new Stack<Integer>(); for (String token : tokens) { try { int num = Integer.parseInt(token); stack.push(num); } catch (NumberFormatException e) { int num2 = stack.pop(); int num1 = stack.pop(); int result; if (token.equals("+")) { result = num1 + num2; } else if (token.equals("-")) { result = num1 - num2; } else if (token.equals("*")) { result = num1 * num2; } else if (token.equals("/")) { result = num1 / num2; } else { throw new IllegalArgumentException("Illegal expression"); } stack.push(result); } } return stack.pop(); } } class Printer { void print(int result, PrintStream out) { out.println(result); } } public class RPNReturningDemo { public static void main(String[] args) throws IOException { Reader reader = new Reader(); Lexer lexer = new Lexer(); Evaluator evaluator = new Evaluator(); Printer printer = new Printer(); while(true) { String expression = reader.read(System.in); String[] tokens = lexer.lex(expression); int result = evaluator.eval(tokens); printer.print(result, System.out); } } } 下面这个程序是同样的功能。每个组件把结果推给下一个组件。但是组件之间互相依赖。 package rpn.pushing; import java.util.*; import java.io.*; class Reader { interface ResultHandler { void handle(String line); } private ResultHandler resultHandler; public ResultHandler getResultHandler() { return resultHandler; } public void setResultHandler(ResultHandler resultHandler) { this.resultHandler = resultHandler; } public void read(InputStream is) throws IOException { Scanner s = new Scanner(is); String line = s.nextLine(); resultHandler.handle(line); } } class Lexer implements Reader.ResultHandler { interface ResultHandler { void handle(String[] tokens); } private ResultHandler resultHandler; public ResultHandler getResultHandler() { return resultHandler; } public void setResultHandler(ResultHandler resultHandler) { this.resultHandler = resultHandler; } public String[] lex(String expression) { return expression.split(" +"); } @Override public void handle(String line) { String[] tokens = lex(line); resultHandler.handle(tokens); } } class Evaluator implements Lexer.ResultHandler { interface ResultHandler { void handle(int result); } private ResultHandler resultHandler; public ResultHandler getResultHandler() { return resultHandler; } public void setResultHandler(ResultHandler resultHandler) { this.resultHandler = resultHandler; } public int eval(String[] tokens) { Stack<Integer> stack = new Stack<Integer>(); for (String token : tokens) { try { int num = Integer.parseInt(token); stack.push(num); } catch (NumberFormatException e) { int num2 = stack.pop(); int num1 = stack.pop(); int result; if (token.equals("+")) { result = num1 + num2; } else if (token.equals("-")) { result = num1 - num2; } else if (token.equals("*")) { result = num1 * num2; } else if (token.equals("/")) { result = num1 / num2; } else { throw new IllegalArgumentException("Illegal expression"); } stack.push(result); } } return stack.pop(); } @Override public void handle(String[] tokens) { int result = eval(tokens); resultHandler.handle(result); } } class Printer implements Evaluator.ResultHandler { private PrintStream printStream; public PrintStream getPrintStream() { return printStream; } public void setPrintStream(PrintStream printStream) { this.printStream = printStream; } void print(int result) { printStream.println(result); } @Override public void handle(int result) { print(result); } } public class RPNPushingDemo { public static void main(String[] args) throws IOException { Reader reader = new Reader(); Lexer lexer = new Lexer(); Evaluator evaluator = new Evaluator(); Printer printer = new Printer(); reader.setResultHandler(lexer); lexer.setResultHandler(evaluator); evaluator.setResultHandler(printer); printer.setPrintStream(System.out); while (true) { reader.read(System.in); } } } 为了避免互相依赖,组件不再实现上游的接口,在主函数中创建连接器。 package rpn.pushing2; import java.util.*; import java.io.*; class Reader { interface ResultHandler { void handle(String line); } private ResultHandler resultHandler; public ResultHandler getResultHandler() { return resultHandler; } public void setResultHandler(ResultHandler resultHandler) { this.resultHandler = resultHandler; } public void read(InputStream is) throws IOException { Scanner s = new Scanner(is); String line = s.nextLine(); resultHandler.handle(line); } } class Lexer { interface ResultHandler { void handle(String[] tokens); } private ResultHandler resultHandler; public ResultHandler getResultHandler() { return resultHandler; } public void setResultHandler(ResultHandler resultHandler) { this.resultHandler = resultHandler; } public String[] lex(String expression) { return expression.split(" +"); } } class Evaluator { interface ResultHandler { void handle(int result); } private ResultHandler resultHandler; public ResultHandler getResultHandler() { return resultHandler; } public void setResultHandler(ResultHandler resultHandler) { this.resultHandler = resultHandler; } public int eval(String[] tokens) { Stack<Integer> stack = new Stack<Integer>(); for (String token : tokens) { try { int num = Integer.parseInt(token); stack.push(num); } catch (NumberFormatException e) { int num2 = stack.pop(); int num1 = stack.pop(); int result; if (token.equals("+")) { result = num1 + num2; } else if (token.equals("-")) { result = num1 - num2; } else if (token.equals("*")) { result = num1 * num2; } else if (token.equals("/")) { result = num1 / num2; } else { throw new IllegalArgumentException("Illegal expression"); } stack.push(result); } } return stack.pop(); } } class Printer { private PrintStream printStream; public PrintStream getPrintStream() { return printStream; } public void setPrintStream(PrintStream printStream) { this.printStream = printStream; } void print(int result) { printStream.println(result); } } public class RPNPushing2Demo { public static void main(String[] args) throws IOException { final Reader reader = new Reader(); final Lexer lexer = new Lexer(); final Evaluator evaluator = new Evaluator(); final Printer printer = new Printer(); reader.setResultHandler(new Reader.ResultHandler() { @Override public void handle(String line) { lexer.lex(line); } }); lexer.setResultHandler(new Lexer.ResultHandler() { @Override public void handle(String[] tokens) { evaluator.eval(tokens); } }); evaluator.setResultHandler(new Evaluator.ResultHandler() { @Override public void handle(int result) { printer.print(result); } }); printer.setPrintStream(System.out); while (true) { reader.read(System.in); } } } 下面这个程序功能还是一样的,每个组件从上游获取数据。当然,连接器在main中创建,组件不互相依赖。 package rpn.pulling; import java.util.*; import java.io.*; class Reader { private InputStream inputStream; private Scanner scanner; public void setInputStream(InputStream inputStream) { this.inputStream = inputStream; this.scanner = new Scanner(inputStream); } public String read() throws IOException { return scanner.nextLine(); } } class Lexer { public interface Source { String get(); } private Source source; public void setSource(Source source) { this.source = source; } public String[] lex() { return source.get().split(" +"); } } class Evaluator { public interface Source { String[] get(); } private Source source; public void setSource(Source source) { this.source = source; } public int eval() { String[] tokens = source.get(); Stack<Integer> stack = new Stack<Integer>(); for (String token : tokens) { try { int num = Integer.parseInt(token); stack.push(num); } catch (NumberFormatException e) { int num2 = stack.pop(); int num1 = stack.pop(); int result; if (token.equals("+")) { result = num1 + num2; } else if (token.equals("-")) { result = num1 - num2; } else if (token.equals("*")) { result = num1 * num2; } else if (token.equals("/")) { result = num1 / num2; } else { throw new IllegalArgumentException("Illegal expression"); } stack.push(result); } } return stack.pop(); } } class Printer { public interface Source { int get(); } private Source source; public void setSource(Source source) { this.source = source; } void print(PrintStream out) { out.println(source.get()); } } public class RPNPullingDemo { public static void main(String[] args) throws IOException { final Reader reader = new Reader(); final Lexer lexer = new Lexer(); final Evaluator evaluator = new Evaluator(); final Printer printer = new Printer(); reader.setInputStream(System.in); lexer.setSource(new Lexer.Source() { @Override public String get() { try { return reader.read(); } catch (IOException e) { e.printStackTrace(); throw new Error("Cannot throw since the interface cannot be changed.", e); } } }); evaluator.setSource(new Evaluator.Source() { @Override public String[] get() { return lexer.lex(); } }); printer.setSource(new Printer.Source() { @Override public int get() { return evaluator.eval(); } }); while (true) { printer.print(System.out); } } } 哪个比较好?有没有更好的?当然这是一个例子,实际程序会更复杂。 反正我印象中,自己写的代码出现过以上好几种。也见过别人的API属于以上某一种或几种。
订阅后,新回复会通过你的通知中心匿名送达。
5 条回复
ppooooll机器人#1 · 2010/12/5
还可以用访问者模式,把所有的东西放到树上,搞个plusNodeVisitor, 之类的。反正什么表达式都可以用逆波兰表达式,但是你有可能需要新加入更多运算符号。也有可能用一种其他方法打印结果,还有可能分析这个表达式一共包含几个数,等等等等 在这种”结构不会变,但是方法变换比较频繁“的问题中,用访问者模式比较好。gof 的书上这么说的,嗯。
wks机器人#2 · 2010/12/5
重点不在RPN上(我本来想用“小写改大写”这个处理函数,但是怕太简单了),而是4个组件的连接。 - 如果不再是每行一个表达式,而是evaluator每次需要读好几行,直到读到"="号为止,不知道一共要读入几个token,怎么办? - 如果没有nextLine(),只有read(numChars),不知道会读到几行,怎么办? - 如果计算的时间很长,不想让程序失去响应,怎么办? - 如果print的信道(如果是socket)不稳定,速度倒是不慢,但抖动很大,等待抖动的时候多读几行行不行? 这些情况下,这几种结构会对程序有什么影响? 【 在 ppooooll 的大作中提到: 】 : 还可以用访问者模式,把所有的东西放到树上,搞个plusNodeVisitor, 之类的。反正什么表达式都可以用逆波兰表达式,但是你有可能需要新加入更多运算符号。也有可能用一种其他方法打印结果,还有可能分析这个表达式一共包含几个数,等等等等 : 在这种”结构不会变,但是方法变换比较频繁“的问题中,用访问者模式比较好。gof 的书上这么说的,嗯。 : -- : ...................
ppooooll机器人#3 · 2010/12/5
另外觉得2和3明显就是作者受了这几天十大队形贴的刺激,程序也队形
ppooooll机器人#4 · 2010/12/5
【 在 wks 的大作中提到: 】 : 重点不在RPN上(我本来想用“小写改大写”这个处理函数,但是怕太简单了),而是4个组件的连接。 : - 如果不再是每行一个表达式,而是evaluator每次需要读好几行,直到读到"="号为止,不知道一共要读入几个token,怎么办? : - 如果没有nextLine(),只有read(numChars),不知道会读到几行,怎么办? : ................... 。。。。。YAGNI 呵呵呵呵。。。。太复杂了就要根据需求分析写代码了
yueyingcs机器人#5 · 2010/12/5
纯论耦合性,第一种耦合性最低,由于是值传参数,因此每一个类都可以单独使用,单独构成服务,可以被很好的复用。第二种方法,为每一个类set了一个handler,增加了组合型耦合,每一个类使用都必须要先初始化好一个handler增加了复用难度。第三种是第二种的简单变种,第二种是 new Handler() handler,然后 setHandler(handler),第三种则是setHandler(new Handler()),没有太多变化,唯一的是引入了匿名类以后代码过长的风险。第四种,改变了数据的流向,前三种都是 第1步->第2步..->第四步的模式,最后一种,则是第四步 wait 第三步,第三步 wait 第二步....直到第一步有数后开始回调。