MVC Architecture

IA Preparation: MVC is not directly assessed in the IB CS exam, but it is the recommended architecture for IA projects. Examiners expect to see clear separation of concerns in well-structured submissions.

Table of Contents

  1. Why This Page Exists
  2. The Three Components
    1. Model – The Data
    2. A Collection Model
    3. View – The Display
    4. Controller – The Logic
  3. How They Interact
  4. MVC in Practice: Student Manager
    1. The View
    2. The Controller
    3. The Application (Wiring It Up)
  5. Why MVC Matters for Your IA
    1. Criterion C (Development)
    2. Adding Features is Easier
    3. Debugging is Easier
  6. Common MVC Mistakes
  7. The MVC Checklist
  8. Quick Check
  9. Code Completion
  10. Spot the Error
  11. Predict the Output
  12. Practice Exercises
    1. Core
    2. Extension
    3. Challenge
  13. Connections

Why This Page Exists

In JavaFX Basics, everything lived in one class – data, display, and logic were mixed together. That works for tiny apps but falls apart quickly. When your IA grows to 5+ classes, you need a structure that keeps things organised.

Model-View-Controller (MVC) is a design pattern that separates your application into three distinct roles. Understanding MVC will help you:

  • Write cleaner IA code that examiners can follow
  • Add features without breaking existing ones
  • Meet Criterion C (Development) expectations for modular design

The Three Components

Model – The Data

The Model holds your application’s data and business logic. It knows nothing about the user interface. It does not know that buttons, text fields, or windows exist.

Responsibilities:

  • Store data (attributes, collections)
  • Validate data (is the input valid?)
  • Perform calculations and operations
  • Read/write data to files

Example: A Student class with name, grade, and validation logic.

public class Student {
    private String name;
    private int grade;

    public Student(String name, int grade) {
        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException("Name cannot be empty");
        }
        if (grade < 0 || grade > 100) {
            throw new IllegalArgumentException("Grade must be 0-100");
        }
        this.name = name;
        this.grade = grade;
    }

    public String getName() { return name; }
    public int getGrade() { return grade; }

    public void setGrade(int grade) {
        if (grade < 0 || grade > 100) {
            throw new IllegalArgumentException("Grade must be 0-100");
        }
        this.grade = grade;
    }

    @Override
    public String toString() {
        return name + " (" + grade + ")";
    }
}

A Collection Model

Most IA projects also need a class that manages a collection of model objects – adding, removing, searching, and sorting.

import java.util.ArrayList;

public class StudentList {
    private ArrayList<Student> students;

    public StudentList() {
        students = new ArrayList<>();
    }

    public void addStudent(Student s) {
        students.add(s);
    }

    public boolean removeByName(String name) {
        for (int i = 0; i < students.size(); i++) {
            if (students.get(i).getName().equals(name)) {
                students.remove(i);
                return true;
            }
        }
        return false;
    }

    public Student findByName(String name) {
        for (int i = 0; i < students.size(); i++) {
            if (students.get(i).getName().equals(name)) {
                return students.get(i);
            }
        }
        return null;
    }

    public ArrayList<Student> getAll() {
        return students;
    }

    public int size() {
        return students.size();
    }
}

The Model never imports javafx.*. If your model class has JavaFX imports, something is in the wrong place.

View – The Display

The View is what the user sees and interacts with. In JavaFX, this is the window with its controls (buttons, text fields, labels, layouts). The View should be as “dumb” as possible – it displays data and forwards user actions, but does not decide what to do with them.

Responsibilities:

  • Create and arrange UI controls
  • Display data provided by the Controller
  • Report user actions (button clicks, text input) to the Controller

Controller – The Logic

The Controller is the coordinator between Model and View. It handles user actions, updates the Model, and tells the View what to display.

Responsibilities:

  • Listen for user actions from the View
  • Call Model methods to add, remove, or modify data
  • Update the View to reflect the current state of the Model
  • Handle errors and show appropriate feedback

How They Interact

┌─────────┐   user action    ┌────────────┐   update data    ┌─────────┐
│  View    │ ──────────────── │ Controller │ ──────────────── │  Model  │
│ (UI)     │                  │  (Logic)   │                  │  (Data) │
│          │ ◄──────────────  │            │ ◄──────────────  │         │
└─────────┘  update display   └────────────┘   return data    └─────────┘
  1. User clicks a button in the View
  2. Controller handles the event – reads input from the View, validates it
  3. Controller updates the Model – adds a student, changes a grade, etc.
  4. Controller updates the View – refreshes the display, shows a message

The Model and View never talk directly to each other. All communication goes through the Controller.


MVC in Practice: Student Manager

Here is a complete example showing MVC with a student list manager. The Model classes are shown above. Below are the View and Controller.

The View

import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class StudentView {
    private TextField nameField;
    private TextField gradeField;
    private Button addBtn;
    private Button removeBtn;
    private Button searchBtn;
    private TextArea display;
    private Label status;

    public Scene createScene() {
        nameField = new TextField();
        nameField.setPromptText("Student name");

        gradeField = new TextField();
        gradeField.setPromptText("Grade (0-100)");

        addBtn = new Button("Add");
        removeBtn = new Button("Remove");
        searchBtn = new Button("Search");

        display = new TextArea();
        display.setEditable(false);
        display.setPrefRowCount(12);

        status = new Label("Ready");

        HBox buttons = new HBox(10, addBtn, removeBtn, searchBtn);
        VBox form = new VBox(10, nameField, gradeField, buttons, status);
        form.setPadding(new Insets(10));

        BorderPane root = new BorderPane();
        root.setCenter(display);
        root.setBottom(form);
        root.setPadding(new Insets(10));

        return new Scene(root, 450, 450);
    }

    // --- Getters for the Controller to access controls ---
    public TextField getNameField() { return nameField; }
    public TextField getGradeField() { return gradeField; }
    public Button getAddBtn() { return addBtn; }
    public Button getRemoveBtn() { return removeBtn; }
    public Button getSearchBtn() { return searchBtn; }
    public TextArea getDisplay() { return display; }
    public Label getStatus() { return status; }
}

Notice: The View creates the controls and provides getters, but has no event handlers and no logic. It does not know what happens when a button is clicked.

The Controller

import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;

public class StudentController {
    private StudentList model;
    private StudentView view;

    public StudentController(StudentList model, StudentView view) {
        this.model = model;
        this.view = view;
        attachHandlers();
        refreshDisplay();
    }

    private void attachHandlers() {
        view.getAddBtn().setOnAction(event -> handleAdd());
        view.getRemoveBtn().setOnAction(event -> handleRemove());
        view.getSearchBtn().setOnAction(event -> handleSearch());
        view.getNameField().setOnAction(event -> handleAdd());
    }

    private void handleAdd() {
        String name = view.getNameField().getText().trim();
        String gradeText = view.getGradeField().getText().trim();

        if (name.isEmpty()) {
            view.getStatus().setText("Error: Name cannot be empty.");
            return;
        }

        int grade;
        try {
            grade = Integer.parseInt(gradeText);
        } catch (NumberFormatException e) {
            view.getStatus().setText("Error: Grade must be a number.");
            return;
        }

        try {
            Student s = new Student(name, grade);
            model.addStudent(s);
            view.getStatus().setText("Added: " + s);
            view.getNameField().clear();
            view.getGradeField().clear();
            refreshDisplay();
        } catch (IllegalArgumentException e) {
            view.getStatus().setText("Error: " + e.getMessage());
        }
    }

    private void handleRemove() {
        String name = view.getNameField().getText().trim();
        if (name.isEmpty()) {
            view.getStatus().setText("Error: Enter a name to remove.");
            return;
        }

        Alert confirm = new Alert(Alert.AlertType.CONFIRMATION);
        confirm.setTitle("Confirm");
        confirm.setHeaderText(null);
        confirm.setContentText("Remove " + name + "?");
        if (confirm.showAndWait().get() == ButtonType.OK) {
            if (model.removeByName(name)) {
                view.getStatus().setText("Removed: " + name);
                view.getNameField().clear();
                refreshDisplay();
            } else {
                view.getStatus().setText("Not found: " + name);
            }
        }
    }

    private void handleSearch() {
        String name = view.getNameField().getText().trim();
        if (name.isEmpty()) {
            view.getStatus().setText("Error: Enter a name to search.");
            return;
        }

        Student found = model.findByName(name);
        if (found != null) {
            view.getStatus().setText("Found: " + found);
        } else {
            view.getStatus().setText("Not found: " + name);
        }
    }

    private void refreshDisplay() {
        view.getDisplay().clear();
        for (int i = 0; i < model.getAll().size(); i++) {
            view.getDisplay().appendText(
                (i + 1) + ". " + model.getAll().get(i) + "\n"
            );
        }
    }
}

The Application (Wiring It Up)

import javafx.application.Application;
import javafx.stage.Stage;

public class StudentApp extends Application {

    @Override
    public void start(Stage stage) {
        StudentList model = new StudentList();
        StudentView view = new StudentView();
        StudentController controller = new StudentController(model, view);

        stage.setTitle("Student Manager");
        stage.setScene(view.createScene());
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

The Application class is tiny. It creates the three MVC components, wires them together, and shows the window. All the real work happens in the Model, View, and Controller.


Why MVC Matters for Your IA

Criterion C (Development)

Examiners look for evidence of modular design. MVC naturally gives you this:

  • Model classes can be tested independently (no GUI needed)
  • The View can be redesigned without changing the logic
  • The Controller can be modified without touching the data layer

Adding Features is Easier

With MVC, adding a new feature follows a predictable pattern:

  1. Model: Add the data or method (e.g., sortByGrade())
  2. View: Add the control (e.g., a “Sort” button)
  3. Controller: Wire the button to the model method

Without MVC, adding a feature often means hunting through one giant class to find where the logic, display, and data are tangled together.

Debugging is Easier

When something goes wrong:

  • Wrong data stored? Check the Model
  • Display looks wrong? Check the View
  • Button does the wrong thing? Check the Controller

Common MVC Mistakes

Putting logic in the View. If your View class has if statements that decide what to do with data, that logic belongs in the Controller.

Putting JavaFX code in the Model. If your Model imports javafx.*, the Model is doing the View’s job. Models should work without any GUI at all.

Skipping the Controller. Some students wire buttons directly to Model methods in the View. This works for tiny apps but becomes impossible to maintain. The Controller is what makes MVC worth it.


The MVC Checklist

Before submitting your IA, check that your code follows these rules:

Rule Check
Model classes have no javafx.* imports  
View creates controls but has no if/decision logic  
Controller handles all event logic  
Model can be tested without launching the GUI  
Each class has one clear responsibility  
Application class only wires components together  

Quick Check

Q1. In MVC, which component stores the application's data and business logic?

Q2. Which component handles user actions and coordinates between the data and the display?

Q3. You notice that your Student model class has import javafx.scene.control.Alert;. What does this indicate?

Q4. A user clicks "Add Student". What is the correct sequence of events in MVC?

Q5. What is a major advantage of keeping all data logic in the Model, separate from the View?


Code Completion

Complete the missing parts of this MVC wiring.

Fill in the blanks: Complete the Application class that wires the MVC components together.

public class BookApp extends Application {

    @Override
    public void start(Stage stage) {
        BookList model = new ;
        BookView view = new BookView();
        BookController ctrl = new BookController();

        stage.setTitle("Book Manager");
        stage.setScene(view.);
        stage.;
    }

    public static void main(String[] args) {
        ;
    }
}

Spot the Error

This Controller method handles adding a student, but violates MVC principles.

Bug Hunt: This Controller method works, but one line violates MVC by doing the View's job.

1private void handleAdd() { 2 String name = view.getNameField().getText().trim(); 3 Student s = new Student(name, 85); 4 model.addStudent(s); 5 view.getNameField().clear(); 6 view.getRoot().getChildren().add(new Label("Added!")); 7 refreshDisplay(); 8}

Pick the correct fix for line 6:


Predict the Output

Predict: When the StudentApp first launches, what text appears in the display TextArea?

// In StudentController constructor:
public StudentController(StudentList model, StudentView view) {
    this.model = model;  // model is a new, empty StudentList
    this.view = view;
    attachHandlers();
    refreshDisplay();    // calls display.clear() then loops over model.getAll()
}

Practice Exercises

Core

  1. Identify the components – You have a Library app with these classes: Book (title, author, ISBN), Library (ArrayList of books, add/remove/search methods), LibraryWindow (text fields, buttons, display area), LibraryController (event handlers). Label each class as Model, View, or Controller.

  2. Fix the violation – A student’s ProductView class contains this code inside a button handler: if (price < 0) { status.setText("Invalid price"); return; }. Explain which MVC component this logic belongs in and why.

Extension

  1. Build a Calculator – Create a simple calculator using MVC:
    • Model: Calculator class with add(), subtract(), multiply(), divide() methods and a result field
    • View: Two text fields for numbers, four operation buttons, a result label
    • Controller: Reads the inputs, calls the correct Model method, displays the result
  2. Add sorting – Extend the Student Manager example: add a “Sort by Grade” button to the View, a sortByGrade() method to the StudentList model (using selection sort), and wire them together in the Controller.

Challenge

  1. Multi-model app – Design (on paper, then code) an MVC application for a school club that manages both Member objects and Event objects. Each event has a list of attending members. Plan your Model classes, decide what the View needs to show, and outline the Controller methods. Then implement it.

Connections


© EduCS.me — A resource hub for IB Computer Science

This site uses Just the Docs, a documentation theme for Jekyll.