Implement ReversePolishStack UI observer to handle operator input and evaluation
Co-Authored-By: td1223
This commit is contained in:
parent
855ce9fd55
commit
38e373bdfc
|
@ -1,10 +1,13 @@
|
||||||
package ic.doc;
|
package ic.doc;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ReversePolishStack {
|
public class ReversePolishStack {
|
||||||
private final Stack<IntOperator> stack = new Stack<>();
|
private final Stack<IntOperator> stack = new Stack<>();
|
||||||
|
private final List<Observer> observers = new LinkedList<>();
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return stack.size();
|
return stack.size();
|
||||||
|
@ -12,6 +15,9 @@ public class ReversePolishStack {
|
||||||
|
|
||||||
public void push(IntOperator intOperator) {
|
public void push(IntOperator intOperator) {
|
||||||
stack.push(intOperator);
|
stack.push(intOperator);
|
||||||
|
|
||||||
|
// Notify observers of push, giving them the updated stack
|
||||||
|
observers.forEach(observer -> observer.actionOnUpdate(toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int evaluateNext() {
|
private int evaluateNext() {
|
||||||
|
@ -36,6 +42,10 @@ public class ReversePolishStack {
|
||||||
throw new ArithmeticException("Invalid notation, too many operators");
|
throw new ArithmeticException("Invalid notation, too many operators");
|
||||||
}
|
}
|
||||||
stack.push(new IntOperator(Integer.toString(result), 0, args -> result));
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,4 +53,18 @@ public class ReversePolishStack {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return stack.stream().map(IntOperator::toString).collect(Collectors.joining(" "));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,44 @@
|
||||||
package ic.doc;
|
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 {
|
public class RpnCalculator {
|
||||||
private static final int DEFAULT_WIDTH = 400;
|
private static final int DEFAULT_WIDTH = 400;
|
||||||
private static final int DEFAULT_HEIGHT = 400;
|
private static final int DEFAULT_HEIGHT = 400;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
// Define the range of numbers that can be input to the calculator
|
||||||
RpnCalculatorGui calculatorGui = RpnCalculatorGui.withDimensions(DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
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();
|
calculatorGui.display();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,33 +4,29 @@ import javax.swing.JFrame;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
import java.util.stream.IntStream;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class RpnCalculatorGui {
|
public class RpnCalculatorGui implements ReversePolishStack.Observer {
|
||||||
|
// Constructor fields
|
||||||
private final int defaultWidth;
|
private final int defaultWidth;
|
||||||
private final int defaultHeight;
|
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;
|
private static final int RESULT_FIELD_WIDTH = 10;
|
||||||
|
|
||||||
// Define the range of numbers that can be input to the calculator
|
public RpnCalculatorGui(int defaultWidth, int defaultHeight, List<IntOperator> operators,
|
||||||
private static final int MIN_INPUT_NUMBER = 0;
|
Consumer<IntOperator> pushOperator, Runnable evaluateAction) {
|
||||||
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) {
|
|
||||||
this.defaultWidth = defaultWidth;
|
this.defaultWidth = defaultWidth;
|
||||||
this.defaultHeight = defaultHeight;
|
this.defaultHeight = defaultHeight;
|
||||||
|
this.operators = operators;
|
||||||
|
this.pushOperator = pushOperator;
|
||||||
|
this.evaluateAction = evaluateAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void display() {
|
public void display() {
|
||||||
|
@ -39,25 +35,28 @@ public class RpnCalculatorGui {
|
||||||
|
|
||||||
JPanel panel = new JPanel();
|
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
|
// Add buttons for each operator
|
||||||
operators.forEach((key, value) -> {
|
operators.forEach(operator -> {
|
||||||
JButton button = new JButton(key);
|
JButton button = new JButton(operator.toString());
|
||||||
|
button.addActionListener(e -> pushOperator.accept(operator));
|
||||||
panel.add(button);
|
panel.add(button);
|
||||||
});
|
});
|
||||||
|
|
||||||
JTextField resultField = new JTextField(RESULT_FIELD_WIDTH);
|
resultField = new JTextField(RESULT_FIELD_WIDTH);
|
||||||
|
resultField.setEditable(false);
|
||||||
panel.add(resultField);
|
panel.add(resultField);
|
||||||
|
|
||||||
JButton evaluateButton = new JButton("⏎");
|
JButton evaluateButton = new JButton("⏎");
|
||||||
|
evaluateButton.addActionListener(e -> evaluateAction.run());
|
||||||
panel.add(evaluateButton);
|
panel.add(evaluateButton);
|
||||||
|
|
||||||
frame.add(panel);
|
frame.add(panel);
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When the stack is evaluated, update the result text box
|
||||||
|
@Override
|
||||||
|
public void actionOnUpdate(String result) {
|
||||||
|
resultField.setText(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue