Существует классический пример перечисления 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()
}
}