Implement ReversePolishStack UI observer to handle operator input and evaluation

Co-Authored-By: td1223
This commit is contained in:
Gleb Koval 2024-11-05 19:00:19 +00:00
parent 855ce9fd55
commit 38e373bdfc
Signed by: cyclane
GPG Key ID: 15E168A8B332382C
4 changed files with 133 additions and 30 deletions

View File

@ -1,10 +1,13 @@
package ic.doc;
import java.util.LinkedList;
import java.util.Stack;
import java.util.List;
import java.util.stream.Collectors;
public class ReversePolishStack {
private final Stack<IntOperator> stack = new Stack<>();
private final List<Observer> observers = new LinkedList<>();
public int getSize() {
return stack.size();
@ -12,6 +15,9 @@ public class ReversePolishStack {
public void push(IntOperator intOperator) {
stack.push(intOperator);
// Notify observers of push, giving them the updated stack
observers.forEach(observer -> observer.actionOnUpdate(toString()));
}
private int evaluateNext() {
@ -36,6 +42,10 @@ public class ReversePolishStack {
throw new ArithmeticException("Invalid notation, too many operators");
}
stack.push(new IntOperator(Integer.toString(result), 0, args -> result));
// Notify observers of evaluation, giving them the result
observers.forEach(observer -> observer.actionOnUpdate(toString()));
return result;
}
@ -43,4 +53,18 @@ public class ReversePolishStack {
public String toString() {
return stack.stream().map(IntOperator::toString).collect(Collectors.joining(" "));
}
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
// Defines an observer to a reverse polish stack
public interface Observer {
// Called whenever the reverse polish stack being observed is modified.
void actionOnUpdate(String result);
}
}

View File

@ -1,12 +1,44 @@
package ic.doc;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import static ic.doc.RpnCalculatorGuiBuilder.rpnCalculatorGui;
public class RpnCalculator {
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 400;
public static void main(String[] args) {
RpnCalculatorGui calculatorGui = RpnCalculatorGui.withDimensions(DEFAULT_WIDTH, DEFAULT_HEIGHT);
// Define the range of numbers that can be input to the calculator
private static final int MIN_INPUT_NUMBER = 0;
private static final int MAX_INPUT_NUMBER = 9;
private static final List<IntOperator> OPERATORS = List.of(
new IntOperator("+", 2, args -> args.get(0) + args.get(1)),
new IntOperator("-", 2, args -> args.get(0) - args.get(1)),
new IntOperator("*", 2, args -> args.get(0) * args.get(1)),
new IntOperator("/", 2, args -> args.get(0) / args.get(1))
);
public static void main(String[] args) {
// Add the numbers 0-9 as operators, then add the standard operators
List<IntOperator> operators = new ArrayList<>();
IntStream.rangeClosed(MIN_INPUT_NUMBER, MAX_INPUT_NUMBER).forEach(i -> {
operators.add(new IntOperator(Integer.toString(i), 0, arguments -> i));
});
operators.addAll(OPERATORS);
ReversePolishStack rps = new ReversePolishStack();
RpnCalculatorGui calculatorGui = rpnCalculatorGui()
.withDefaultWidth(DEFAULT_WIDTH)
.withDefaultHeight(DEFAULT_HEIGHT)
.withOperators(operators)
.withPushOperator(rps::push)
.withEvaluateAction(rps::evaluate)
.build();
rps.addObserver(calculatorGui);
calculatorGui.display();
}
}

View File

@ -4,33 +4,29 @@ import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.util.Map;
import java.util.stream.IntStream;
import java.util.List;
import java.util.function.Consumer;
public class RpnCalculatorGui {
public class RpnCalculatorGui implements ReversePolishStack.Observer {
// Constructor fields
private final int defaultWidth;
private final int defaultHeight;
private final List<IntOperator> operators;
private final Consumer<IntOperator> pushOperator;
private final Runnable evaluateAction;
// UI elements
JTextField resultField;
private static final int RESULT_FIELD_WIDTH = 10;
// Define the range of numbers that can be input to the calculator
private static final int MIN_INPUT_NUMBER = 0;
private static final int MAX_INPUT_NUMBER = 9;
private static final Map<String, Object> operators = Map.of(
"+", new Object(),
"-", new Object(),
"*", new Object(),
"/", new Object()
);
public static RpnCalculatorGui withDimensions(int defaultWidth, int defaultHeight) {
return new RpnCalculatorGui(defaultWidth, defaultHeight);
}
private RpnCalculatorGui(int defaultWidth, int defaultHeight) {
public RpnCalculatorGui(int defaultWidth, int defaultHeight, List<IntOperator> operators,
Consumer<IntOperator> pushOperator, Runnable evaluateAction) {
this.defaultWidth = defaultWidth;
this.defaultHeight = defaultHeight;
this.operators = operators;
this.pushOperator = pushOperator;
this.evaluateAction = evaluateAction;
}
public void display() {
@ -39,25 +35,28 @@ public class RpnCalculatorGui {
JPanel panel = new JPanel();
// Add buttons for each number input
IntStream.rangeClosed(MIN_INPUT_NUMBER, MAX_INPUT_NUMBER).forEach(n -> {
JButton button = new JButton(Integer.toString(n));
panel.add(button);
});
// Add buttons for each operator
operators.forEach((key, value) -> {
JButton button = new JButton(key);
operators.forEach(operator -> {
JButton button = new JButton(operator.toString());
button.addActionListener(e -> pushOperator.accept(operator));
panel.add(button);
});
JTextField resultField = new JTextField(RESULT_FIELD_WIDTH);
resultField = new JTextField(RESULT_FIELD_WIDTH);
resultField.setEditable(false);
panel.add(resultField);
JButton evaluateButton = new JButton("");
evaluateButton.addActionListener(e -> evaluateAction.run());
panel.add(evaluateButton);
frame.add(panel);
frame.setVisible(true);
}
// When the stack is evaluated, update the result text box
@Override
public void actionOnUpdate(String result) {
resultField.setText(result);
}
}

View File

@ -0,0 +1,48 @@
package ic.doc;
import java.util.List;
import java.util.function.Consumer;
public class RpnCalculatorGuiBuilder {
private int defaultWidth;
private int defaultHeight;
private List<IntOperator> operators;
private Consumer<IntOperator> pushOperator;
private Runnable evaluateAction;
private RpnCalculatorGuiBuilder() {}
public static RpnCalculatorGuiBuilder rpnCalculatorGui() {
return new RpnCalculatorGuiBuilder();
}
public RpnCalculatorGuiBuilder withDefaultWidth(int defaultWidth) {
this.defaultWidth = defaultWidth;
return this;
}
public RpnCalculatorGuiBuilder withDefaultHeight(int defaultHeight) {
this.defaultHeight = defaultHeight;
return this;
}
public RpnCalculatorGuiBuilder withOperators(List<IntOperator> operators) {
this.operators = operators;
return this;
}
public RpnCalculatorGuiBuilder withPushOperator(Consumer<IntOperator> operatorConsumer) {
this.pushOperator = operatorConsumer;
return this;
}
public RpnCalculatorGuiBuilder withEvaluateAction(Runnable evaluateAction) {
this.evaluateAction = evaluateAction;
return this;
}
public RpnCalculatorGui build() {
return new RpnCalculatorGui(defaultWidth, defaultHeight, operators, pushOperator,
evaluateAction);
}
}