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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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