Как я могу создать перечисление Java двоичных и унарных операторов / операций? - PullRequest
0 голосов
/ 30 октября 2019

Существует классический пример перечисления java "Оператор", который содержит связанную логику операций, например:

    PLUS    ("+", (l, r) -> l + r),
    MINUS   ("-", (l, r) -> l - r),
    MULTIPLY("*", (l, r) -> l * r),
    DIVIDE  ("/", (l, r) -> l / r);

    private final String symbol;
    private final DoubleBinaryOperator binaryOperator;

    private Operation(final String symbol, final DoubleBinaryOperator binaryOperator) {
        this.symbol = symbol;
        this.binaryOperator = binaryOperator;
    }

Есть ли способ изменить такую ​​реализацию для поддержки функций, которые не являются BinaryOperators (например, унарный оператор)? Представьте, что у меня есть «калькулятор» с использованием оператора выше, и я хочу добавить оператор «SIN» или «COS». Каков наилучший способ сделать это (в ванильной Java)?

Ранее я сталкивался с этим примером, используя Swift из класса iOS Пола Хаггерти через Стэнфордский университет. Мы можем видеть, что перечисление «Operation» грубо переводится в перечисление различных функциональных интерфейсов на языке Java, но возможно ли что-то подобное в Java?

private enum Operation {
        case constant(Double)
        case nullaryOperation(() -> Double)
        case unaryOperation((Double) -> Double)
        case binaryOperation((Double, Double) -> Double)
        case equals
    }

    private var operations: Dictionary<String, Operation> = [
        "π"   : Operation.constant(Double.pi),
        "e"   : Operation.constant(M_E),
        "RND" : Operation.nullaryOperation(randomDouble),
        "√"   : Operation.unaryOperation(sqrt),
        "∛"   : Operation.unaryOperation({pow($0, 1.0/3.0)}),     // Cubed root function
        "x²"  : Operation.unaryOperation({$0 * $0}),
        "x³"  : Operation.unaryOperation({$0 * $0 * $0}),
        "sin" : Operation.unaryOperation(sin),
        "cos" : Operation.unaryOperation(cos),
        "tan" : Operation.unaryOperation(tan),
        "log" : Operation.unaryOperation(log10),
        "ln"  : Operation.unaryOperation(log),
        "±"   : Operation.unaryOperation({-$0}),
        "×"   : Operation.binaryOperation({$0 * $1}),
        "÷"   : Operation.binaryOperation({$0 / $1}),
        "+"   : Operation.binaryOperation({$0 + $1}),
        "−"   : Operation.binaryOperation({$0 - $1}),
        "="   : Operation.equals
    ]

    mutating func performOperation(_ symbol: String) {
        if let operation = operations[symbol] {
            switch operation {
            case .constant(let value):
                accumulator = (value, "\(symbol)")
            case .nullaryOperation(let function):
                let result = function()
                accumulator = (result, formatValue(result))
            case .unaryOperation(let function):
                if accumulator.value != nil {
                    let description : String
                    if resultIsPending {
                        // Unary operations execute on the current operand. If there
                        // is a pending operation the description of the pending
                        // operation needs to be included in the description. Include the
                        // pending operation description before the unary operation
                        // description and clear the pending operation description since
                        // it has been accounted for here.
                        //
                        description = pendingBinaryOperation!.description + "\(symbol)(\(accumulator.description))"
                        pendingBinaryOperation!.description = ""
                    }
                    else {
                        description = "\(symbol)(\(accumulator.description))"
                    }
                    accumulator = (function(accumulator.value!), description)
                }
            case .binaryOperation(let function):
                performPendingBinaryOperation()
                if accumulator.value != nil {
                    pendingBinaryOperation = PendingBinaryOperation(function: function,
                                                                    firstOperand: accumulator.value!,
                                                                    description: "\(accumulator.description) \(symbol) ")
                    accumulator = (nil, pendingBinaryOperation!.description)
                }
            case .equals:
                performPendingBinaryOperation()
            }
        }
...