i am trying to learn mvc (model view controller). there are many texts out there explaining what mvc is. but not many explaining how to actually code mvc. i found a bunch of questions here asking about mvc. some seem to contradict each other (view observe model or not, controller listens to view or not).
i made a simple calculator in java swing to try to implement mvc so i can get a review from you whether you think i have done it right or not. the calculator is super simple so the code can concentrate on the mvc aspects.
the main class
public class Main { public static void main(String[] args) { Model model = new Model(); View view = new View(); Controller controller = new Controller(model, view); view.setController(controller); controller.start(); } }
the model
public class Model { public int calculate(int i1, String op, int i2) { int res; switch (op) { case "+": res = i1 + i2; break; case "-": res = i1 - i2; break; default: throw new RuntimeException("impossible operator"); } return res; } }
the view
public class View { Controller controller; JLabel result; public void setController(Controller controller) { this.controller = controller; } public void show() { JFrame frame = new JFrame("calculator mvc"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); JTextField input1 = new JTextField(10); JComboBox<String> operand = new JComboBox<String>( new String[] { "+", "-" }); JTextField input2 = new JTextField(10); JButton calcbutton = new JButton("calculate"); result = new JLabel(" "); result.setBorder(BorderFactory.createLineBorder(Color.BLACK)); calcbutton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String s1 = input1.getText(); String op = operand.getItemAt(operand.getSelectedIndex()); String s2 = input2.getText(); controller.handleUserInput(s1, op, s2); } }); panel.add(input1); panel.add(operand); panel.add(input2); panel.add(calcbutton); panel.add(result); frame.add(panel); frame.pack(); frame.setVisible(true); } public void setResult(String res) { this.result.setText(res); } }
the controller
public class Controller { Model model; View view; public Controller(Model model, View view) { this.model = model; this.view = view; } public void handleUserInput(String s1, String op, String s2) { int i1 = Integer.parseInt(s1); int i2 = Integer.parseInt(s2); int res = this.model.calculate(i1, op, i2); this.view.setResult(String.valueOf(res)); } public void start() { this.view.show(); } }
some comments:
i took the mvc approach where view does not observe model. instead controller talks to view. in this case model does not have any state to observe anyway.
the operators in model could have been done in command pattern or strategy pattern. but that would have added at least three more classes (or interfaces). i decided to keep it simple.
model gets ints and returns ints. view gives strings and gets strings. controller is the one translating between the two.
is this good mvc?
just for comparison here is the code without mvc
public class MainNotMvc { public static void main(String[] args) { JFrame frame = new JFrame("calculator not mvc"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); JTextField input1 = new JTextField(10); JComboBox<String> operand = new JComboBox<String>( new String[] { "+", "-" }); JTextField input2 = new JTextField(10); JButton calcbutton = new JButton("calculate"); JLabel result = new JLabel(" "); result.setBorder(BorderFactory.createLineBorder(Color.BLACK)); calcbutton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int i1 = Integer.parseInt(input1.getText()); String op = operand.getItemAt(operand.getSelectedIndex()); int i2 = Integer.parseInt(input2.getText()); int res; switch (op) { case "+": res = i1 + i2; break; case "-": res = i1 - i2; break; default: throw new RuntimeException("impossible operator"); } result.setText(String.valueOf(res)); } }); panel.add(input1); panel.add(operand); panel.add(input2); panel.add(calcbutton); panel.add(result); frame.add(panel); frame.pack(); frame.setVisible(true); } }
code in git: https://gitlab.com/lesmana/java-swing-simple-calculator-mvc