-
Notifications
You must be signed in to change notification settings - Fork 544
Expand file tree
/
Copy pathCalculator.java
More file actions
179 lines (153 loc) · 5.66 KB
/
Calculator.java
File metadata and controls
179 lines (153 loc) · 5.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package simplejavacalculator;
import static java.lang.Double.NaN;
import static java.lang.Math.*;
import java.util.HashMap;
import java.util.Map;
import simplejavacalculator.behavioral.command.*;
import simplejavacalculator.behavioral.strategy.*;
import simplejavacalculator.creational.*;
import simplejavacalculator.structural.*;
import simplejavacalculator.structural.adapter.*;
import simplejavacalculator.structural.decorator.*;
public class Calculator {
public enum BiOperatorModes {
normal, add, minus, multiply, divide, xpowerofy
}
public enum MonoOperatorModes {
square, squareRoot, oneDividedBy, cos, sin, tan, log, rate, abs, ln
}
private Double currentValue = 0.0;
private Double num1, num2;
private BiOperatorModes mode = BiOperatorModes.normal;
private final Map<String, CalculatorOperation> operations;
private final OperationFactory factory;
private final CalculatorBuilder builder;
private final CommandHistory history;
private CalculationStrategy strategy;
public Calculator() {
this.operations = new HashMap<>();
this.factory = new OperationFactory();
this.builder = new CalculatorBuilder();
this.history = new CommandHistory();
this.strategy = new BasicStrategy();
initializeOperations();
}
private void initializeOperations() {
// Basic operations with factory and logging decorator
Operation addOp = factory.createOperation("add");
Operation subOp = factory.createOperation("subtract");
Operation mulOp = factory.createOperation("multiply");
Operation divOp = factory.createOperation("divide");
operations.put("add", new LoggingDecorator(new CalculatorOperationAdapter(addOp)));
operations.put("subtract", new LoggingDecorator(new CalculatorOperationAdapter(subOp)));
operations.put("multiply", new LoggingDecorator(new CalculatorOperationAdapter(mulOp)));
operations.put("divide", new LoggingDecorator(new CalculatorOperationAdapter(divOp)));
// Scientific operations with adapter
operations.put("sin", new LoggingDecorator(
new ScientificAdapter(new TrigonometricOperation("sin"), "sin")
));
operations.put("cos", new LoggingDecorator(
new ScientificAdapter(new TrigonometricOperation("cos"), "cos")
));
operations.put("tan", new LoggingDecorator(
new ScientificAdapter(new TrigonometricOperation("tan"), "tan")
));
}
private class CalculatorOperationAdapter implements CalculatorOperation {
private final Operation operation;
public CalculatorOperationAdapter(Operation operation) {
this.operation = operation;
}
@Override
public Double execute(Double... numbers) {
return operation.execute(numbers);
}
@Override
public String getDescription() {
return operation.getDescription();
}
}
public void setStrategy(CalculationStrategy strategy) {
this.strategy = strategy;
}
public Double getCurrentValue() {
return currentValue;
}
public void setValue(Double value) {
this.currentValue = value;
}
public void executeCommand(CalculatorCommand command) {
history.executeCommand(command);
}
public void undo() {
history.undo();
}
public void redo() {
history.redo();
}
private Double calculateBiImpl() {
if (mode.equals(BiOperatorModes.normal)) {
return num2;
}
String operationType = null;
switch (mode) {
case add: operationType = "add"; break;
case minus: operationType = "subtract"; break;
case multiply: operationType = "multiply"; break;
case divide: operationType = "divide"; break;
case xpowerofy: return strategy.calculate(num1, num2);
}
if (operationType != null) {
CalculatorOperation operation = operations.get(operationType);
if (operation != null) {
return operation.execute(num1, num2);
}
}
throw new Error("Invalid operation");
}
public Double calculateBi(BiOperatorModes newMode, Double num) {
if (mode.equals(BiOperatorModes.normal)) {
num2 = 0.0;
num1 = num;
mode = newMode;
currentValue = num1;
return NaN;
} else {
num2 = num;
num1 = calculateBiImpl();
mode = newMode;
currentValue = num1;
return num1;
}
}
public Double calculateEqual(Double num) {
return calculateBi(BiOperatorModes.normal, num);
}
public Double reset() {
num2 = 0.0;
num1 = 0.0;
currentValue = 0.0;
mode = BiOperatorModes.normal;
return NaN;
}
public Double calculateMono(MonoOperatorModes newMode, Double num) {
Double result = switch (newMode) {
case square -> num * num;
case squareRoot -> Math.sqrt(num);
case oneDividedBy -> 1 / num;
case cos -> Math.cos(Math.toRadians(num));
case sin -> Math.sin(Math.toRadians(num));
case tan -> {
if (num == 0 || num % 180 == 0) yield 0.0;
if (num % 90 == 0.0 && num % 180 != 0.0) yield NaN;
yield Math.tan(Math.toRadians(num));
}
case log -> log10(num);
case ln -> log(num);
case rate -> num / 100;
case abs -> Math.abs(num);
};
currentValue = result;
return result;
}
}