返回信息流这是一个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属于以上某一种或几种。
这是一条镜像帖。来源:北邮人论坛 / java / #16703同步于 2010/12/5
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
不怕脑残的进来
wks
2010/12/5镜像同步5 回复
订阅后,新回复会通过你的通知中心匿名送达。
5 条回复
还可以用访问者模式,把所有的东西放到树上,搞个plusNodeVisitor, 之类的。反正什么表达式都可以用逆波兰表达式,但是你有可能需要新加入更多运算符号。也有可能用一种其他方法打印结果,还有可能分析这个表达式一共包含几个数,等等等等
在这种”结构不会变,但是方法变换比较频繁“的问题中,用访问者模式比较好。gof 的书上这么说的,嗯。
重点不在RPN上(我本来想用“小写改大写”这个处理函数,但是怕太简单了),而是4个组件的连接。
- 如果不再是每行一个表达式,而是evaluator每次需要读好几行,直到读到"="号为止,不知道一共要读入几个token,怎么办?
- 如果没有nextLine(),只有read(numChars),不知道会读到几行,怎么办?
- 如果计算的时间很长,不想让程序失去响应,怎么办?
- 如果print的信道(如果是socket)不稳定,速度倒是不慢,但抖动很大,等待抖动的时候多读几行行不行?
这些情况下,这几种结构会对程序有什么影响?
【 在 ppooooll 的大作中提到: 】
: 还可以用访问者模式,把所有的东西放到树上,搞个plusNodeVisitor, 之类的。反正什么表达式都可以用逆波兰表达式,但是你有可能需要新加入更多运算符号。也有可能用一种其他方法打印结果,还有可能分析这个表达式一共包含几个数,等等等等
: 在这种”结构不会变,但是方法变换比较频繁“的问题中,用访问者模式比较好。gof 的书上这么说的,嗯。
: --
: ...................
【 在 wks 的大作中提到: 】
: 重点不在RPN上(我本来想用“小写改大写”这个处理函数,但是怕太简单了),而是4个组件的连接。
: - 如果不再是每行一个表达式,而是evaluator每次需要读好几行,直到读到"="号为止,不知道一共要读入几个token,怎么办?
: - 如果没有nextLine(),只有read(numChars),不知道会读到几行,怎么办?
: ...................
。。。。。YAGNI 呵呵呵呵。。。。太复杂了就要根据需求分析写代码了
纯论耦合性,第一种耦合性最低,由于是值传参数,因此每一个类都可以单独使用,单独构成服务,可以被很好的复用。第二种方法,为每一个类set了一个handler,增加了组合型耦合,每一个类使用都必须要先初始化好一个handler增加了复用难度。第三种是第二种的简单变种,第二种是 new Handler() handler,然后 setHandler(handler),第三种则是setHandler(new Handler()),没有太多变化,唯一的是引入了匿名类以后代码过长的风险。第四种,改变了数据的流向,前三种都是 第1步->第2步..->第四步的模式,最后一种,则是第四步 wait 第三步,第三步 wait 第二步....直到第一步有数后开始回调。