【问题标题】:Android calculator App good practice?Android计算器App好习惯?
【发布时间】:2014-08-08 14:43:39
【问题描述】:

大家好,我是 Android 世界的新手,我正在尝试构建一个中等难度的计算器应用程序。我想出了这种结构,但还没有实现任何东西,因为我有点怀疑这是否是正确的方法。所以我来了:

我有一个 Operand 接口,它带有一种称为“getValue()”的方法,它应该返回一个双精度类型,以及一些实现该接口的其他对象,从而实现该“getValue()”方法:

  • Expression,我考虑过让它成为一个具有私有成员字段的对象,该字段将存储所有操作,所以这个 Expression Object 会有这样的东西:

    public class Expression implements Operand {
    
        private List<Operation> operationList;
        ... 
    }
    

    operationList 将是一个 ArrayList,其中 Operation 是另一个对象,它涉及两个操作数(因此两个操作数接口作为类型)与一个 Operator 对象绑定在一起,该对象具有一个枚举类型,表示涉及这两个操作数的操作是否为SUM、DIV、MUL 或 SUB。比如:

    public class Operation {
    
        private Operand operand1;
        private Operand operand2;
        private Operator operator;          
    
        public Operation(Operand operand1, Operator operator, Operand operand2) {
             this.operand1 = operand1;
             this.operand2 = operand2;
             this.operator = operator;
        }
    
        public double getResult() {
             if (operator.getType() == Operator.Type.SUM) {
                 return operand1.getValue() + operand2.getValue();
             }
             else if (operator.getType() == Operator.Type.SUB) {
                 return operand1.getValue() - operand2.getValue();
             }
             else if (operator.getType() == Operator.Type.MUL) {
                 return operand1.getValue() * operand2.getValue();
             }
             else if (operator.getType() == Operator.Type.DIV) {
                 return operand1.getValue() / operand2.getValue();
             }
             return 0;
        }
        ... 
    }
    

通过这种方式,即使在像“3 + (4 * 3 - 2 * (4 - 1) / 2 + 5))”这样的表达式中有子表达式,由于接口的原因,它也会像操作数一样被计算,在特别是在这种情况下:

 operator   All this is another Expression object (a sub-expression that is treated 
   |         |                                     like an Operand
   | ________|____________                         cause it implements the Operand
 3 + (4 * 3 - 2 * (4 - 1))                         interface).
 |
Operand operand1
  • 实现 Operand 的数字类,它将是一个用于双精度值的简单包装器类,并将在其实现的 getValue() 方法中返回该双精度值。

  • 具有枚举类型的函数类,表示它是 SIN、COS、TAN、ARCSIN、ARCCOS、ARCTAN、LOG 还是 LN 函数,始终使用 getValue() 方法返回计算的双精度结果功能;

  • 实用程序,这个类可能会被误解:它是用于诸如求幂、平方根、数字的百分比或其阶乘之类的操作的类。这里的想法是再次使用枚举类型来区分操作的类型。我知道取幂本身就是一个运算,但对我来说最好让它远离前面解释的 Operation 类,因为结构和计算是不同的(我想将 Exponentiation 视为 Operand 类型,而不是 Operation ,对我来说,一个操作只涉及两个操作数和一个操作符,正如我之前所说的)。

然后我知道,给定这样的表达式:

3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2

数据结构是:

  Operand                              Operand
    |                                  |   
3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2
|       ¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯¯  
Operand             Operand

4 个操作数,因此 3 个操作,但我需要建立优先级,所以我认为我应该遍历 operationList(Expression 对象中的私有字段)以获得这样的优先级,因为我的数据结构就像(基于此表达式,伪代码):

列表:

- Item n° 1 -> Operation(Number(3), Operator(Operator.Type.SUM), Number(4));
- Item n° 2 -> Operation(Number(4), Operator(Operator.Type.MUL), Expression("(5 + 2) - √4 + sin(4) + 3²"));
- Item n° 3 -> Operation(Expression("(5 + 2) - √4 + sin(4) + 3²"), Operator(Operator.Type.DIV), Number(2));

遍历这个列表我可以发现操作编号 2(项目编号 2)必须在操作编号 1 之前执行。但我认为这种方式不太好,因为您看到我需要整理所有 ArrayList每次我在执行操作 N°2 并获得双重结果时从操作原因中获得结果时,我需要为该结果创建一个 Number() 对象,以再次将其视为操作数并以某种方式重新组织 ArrayList第一个操作不再将 Number(4) 作为第二个操作数,而是将来自操作 2 getResult() 的新结果包装在一个 Number 对象中。此外,位置 3 处的操作不再将表达式作为第一个操作数,而是将前一个操作的结果作为操作数。

在我看来,这种结构处理起来有点贵,我想问是否有人遇到同样的问题并提出了更好的解决方案,或者这个解决方案可能没问题。另一种方法是将完整的 Expression 存储为 String 并使用 RegExp 对其进行解析,以确定顺序的所有操作。这是一个更好的解决方案吗,因为我想让用户在输入表达式时动态更改操作数,即如果他写了前面的表达式:

3 + 4 * ((5 + 2) - √4 + sin(4) + 3²) / 2

如果他想在单击“等于”按钮执行操作之前将 √4 更改为 ln(6),他可以这样做。所以我想使用以前的 ArrayList 很难管理这样的变化,因为我需要保持我的表达式的每个操作数的位置......

例如如何谷歌在他的计算器应用程序中执行此操作,例如如果你看 -> https://www.google.it/search?q=2%2B2&oq=2%2B2&aqs=chrome.0.69i59j0l2j69i65l2j0.1141j0j7&sourceid=chrome&es_sm=94&ie=UTF-8#q=+3+%2B+4+*+((5+%2B+2)+-+sin(4)+%2B+3)+%2F+2

我知道它是 Javascript,但我猜每种语言的逻辑都是相同的。

您认为可能的解决方案是什么?感谢您的关注!

编辑:我不明白的东西:

  /**
       Evaluates a simple expression (such as "1+1") and returns its value.
       @throws SyntaxException in these cases:
       <ul>
       <li> the expression is not well-formed
       <li> the expression is a definition (such as "a=1+1")
       <li> the expression is an implicit function (such as "x+1")
       </ul>
     */
    public synchronized double eval(String expression) throws SyntaxException {
        return compiler.compileSimple(this, expression).eval();
    }

该方法调用Compiler编译对象的.compileSimple:

Function compileSimple(Symbols symbols, String expression) throws SyntaxException {
    rpn.setConsumer(simpleCodeGen.setSymbols(symbols));
    lexer.scan(expression, rpn);
    return simpleCodeGen.getFun();
}

它返回一个 Function 对象,然后对其调用 eval() 方法。查看 Function.eval() 方法我看到了这个:

/**
       Evaluates an arity-0 function (a function with no arguments).
       @return the value of the function
    */
    public double eval() {
        throw new ArityException(0);
    }

方法 eval 必须返回一个 double 类型,并且实现抛出一个 ArityException 具有这个实现:

public class ArityException extends RuntimeException {
    public ArityException(String mes) {
        super(mes);
    }

    public ArityException(int nArgs) {
        this("Didn't expect " + nArgs + " arguments");
    }
}

如果抛出 ArityException,它如何评估字符串并返回一个双精度值?

【问题讨论】:

    标签: java android calculator


    【解决方案1】:

    您可能想看看该平台附带的官方 Android 计算器应用程序的源代码。

    我认为Logic.java 将是您正在寻找的课程。它有用于格式化、检查运算符、估值等的代码:Android Calculator

    编辑

    Android 计算器使用 Arity 算术引擎,这是一个开源库,用于计算以字符串表示的算术表达式。我找不到该项目的活动链接,它已从 code.google.com 中删除。但您可以参考以下链接了解更多信息:

    1. http://www.developerfusion.com/project/62854/arity/
    2. Download arity .jar

    【讨论】:

    • 感谢您的链接,我看到它使用了一个名为 arity 的 JAR 库,它接受一个表达式字符串并像操作一样评估它。所以我可以假设当用户最终按下等号按钮时,我可能应该实现有点 .eval() 函数来评估完整的表达式字符串?
    • 是的,它使用了 arity 引擎。实际上,许多计算器应用程序都使用该库。我编辑了答案以获取更多信息
    • 感谢分享,我查看了arity代码并无法理解一件事:它如何通过操作评估字符串?如果您查看 Symbols 对象的 eval() 方法,您会发现它调用 Compiler 成员 var 的 compiler.compileSimple(this, expression) ,而后者又返回一个 Function 对象并在该对象上调用 eval() 方法,但该方法的实现会引发 ArityException 类型的异常并且不返回双精度值。 . 请检查我的编辑。
    猜你喜欢
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    相关资源
    最近更新 更多