MVC architecture follows the separation of concerns principle to the letter. In fact, each letter in the MVC acronym represents an essential section of your application. This article explores each section of MVC architecture in detail and shows you how to use them to develop software.

What Is the Model?

The Model of MVC architecture is a principal component of the design pattern. This is because the model of your application stores the data logic. The model dictates how you store and retrieve your data.

For an application that uses the MVC controller architecture, data is an essential component of its operation.

What Is the View?

The View of MVC architecture is the user interface (UI) of your application. The UI is what a user sees on their device when they interact with your program. The state of the View relies on the data stored using the model.

What Is the Controller?

You can think of the Controller as a bridge between the Model and View components.

When a user supplies data through your user interface (the View), the View passes that data to the Controller. The Controller uses that data to update the database (through the Model). The Controller also pulls data from the database (through the Model) and returns it to the View.

In addition to being a data channel, the Controller is also the brains of the operation. It decides what operation to conduct on which data, and what data to return to the UI.

How Does it All Come Together?

MVC architecture creates a semi-closed loop that relies on all components to function adequately. The following illustration demonstrates how MVC architecture operates.

MVC pattern diagram

As you can see from the illustration above, the MVC application receives an initial input of data from a user through the UI. Then the application passes that data through the different components of the MVC architecture, and in some instances, manipulates that data in the Controller component.

Applying MVC Architecture

Say you’re developing an application for a gas station that wants to create a record of all the gas sold at the station and help the gas attendants with price calculation. Using MVC architecture, you’d start with the Model, then move on to the Controller, and after you’ve figured out all the logic of your application, you can implement the View.

When creating a model for your application, you’ll need to know what type of data you want to store, how you want to store that data, and how accessible you want that data to be.

Creating the Application Model

//Java library
import java.io.Serializable;
public class GasPriceModel implements Serializable{
 //attributes
 private static final long serialVersionUID = 1L;
 private String driverName;
 private float gasAmount;
 private String gasType;
 private float cost;
// default constructor
 public GasPriceModel() {
 this.driverName = "";
 this.gasAmount = 0.00f;
 this.gasType = "";
 this.cost = 0.00f;
 }
 //primary constructors
 public GasPriceModel(String driverName, float gasAmount, String gasType, float cost) {
 this.driverName = driverName;
 this.gasAmount = gasAmount;
 this.gasType = gasType;
 this.cost = cost;
 }
 //getters and setters that retrieve and manipulate data
 public String getDriverName() {
 return driverName;
 }
 public void setDriverName(String driverName) {
 this.driverName = driverName;
 }
 public float getGasAmount() {
 return gasAmount;
 }
 public void setGasAmount(float gasAmount) {
 this.gasAmount = gasAmount;
 }
 public String getGasType() {
 return gasType;
 }
 public void setGasType(String gasType) {
 this.gasType = gasType;
 }
 public float getCost() {
 return cost;
 }
 public void setCost(float cost) {
 this.cost = cost;
 }
}

There are several important things to identify in the Model code above. The first is that it implements the Serializable interface. This interface allows you to save the state of every object created using the GasPriceModel class by converting it into a byte stream. Implementing the Serializable interface means that you also need to create a version ID, which is what the first attribute in the class above does.

The other four attributes in the GasPriceModel class are equally important because they tell you who’s going to access the data that this model will create. It also tells you what type of data the model will store (strings and floats).

Creating the Application Controller

//Java Libraries
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class GasPriceController {
 //calculates the cost of a customer's gas and returns it
 public float calculateCost(float amount, String gasType){
 float cost = 0.00f;
 final float dieselPrice = 4.925f;
 final float premiumPrice = 5.002f;
 final float regularPrice = 4.680f;
 
 if (gasType == "Diesel")
 cost = amount * dieselPrice;
 if (gasType == "Premium")
 cost = amount * premiumPrice;
 if (gasType == "Regular")
 cost = amount * regularPrice;
 
 return cost;
 }
 
 //saves the data from each sale to a file using the model
 public boolean saveEntry(GasPriceModel data){
 try {

 FileOutputStream fs = new FileOutputStream(new File("data.dat"), true);
 ObjectOutputStream os = new ObjectOutputStream(fs);
 os.writeObject(data);
 os.flush();
 os.close();
 return true;
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 }
 return false;
 }
}

The Controller above does two things, it performs a calculation on the data received from the view, and decides what data to return. The Controller above also uses the application model to store the objects created from the view input, using the saveEntry() method.

Creating the Application View

//Java libraries
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;


public class GasPriceView extends JFrame implements ActionListener {
 
 //attributes
 private static final long serialVersionUID = 1L;
 private GasPriceController controller;
 private JLabel driverName;
 private JTextField nameField;
 private JLabel gasAmount;
 private JTextField amountField;
 private JLabel gasType;
 private JComboBox<String> typeCombo;
 private JButton btnClear;
 private JButton btnSave;
 private static final String[] type =
 {"Diesel", "Premium", "Regular"};
 
 //default constructor
 public GasPriceView() {
 this(new GasPriceController());
 }
 
 //primary constructor that cause the UI
 public GasPriceView(GasPriceController controller) {
 
 super("Gas Sale Application");
 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 setSize(400,500);
 setVisible(true);
 
 this.controller = controller;
 
 configureView();
 }

 //generate the UI for the application
 private void configureView() {
 
 setLayout(new BorderLayout());
 JPanel pnl = new JPanel(new GridLayout(4,2,2,2));
 
 driverName = new JLabel("Driver's Name:");
 pnl.add(driverName);
 nameField = new JTextField();
 pnl.add(nameField);
 gasAmount = new JLabel("Gas Amount (Gallon):");
 pnl.add(gasAmount);
 amountField = new JTextField();
 pnl.add(amountField);
 gasType = new JLabel("Gas Type:");
 pnl.add(gasType);
 typeCombo = new JComboBox<String>(type);
 pnl.add(typeCombo);
 btnClear = new JButton("Clear");
 pnl.add(btnClear);
 btnSave = new JButton("Save");
 pnl.add(btnSave );
 
 add(pnl, BorderLayout.CENTER);
 
 ActionListener();
 
 
 }
 //listens for the click of one of two buttons
 public void ActionListener() {
 btnClear.addActionListener(this);
 
 btnSave.addActionListener(this);
 }
 
 
 //performs an action if a specific button is clicked
 @Override
 public void actionPerformed(ActionEvent ev) {
 
 if(ev.getSource().equals(btnClear)) {
 nameField.setText("");
 amountField.setText("");
 }
 
 if(ev.getSource().equals(btnSave)){
 
 String gasType = (String) typeCombo.getSelectedItem();
 float gasAmount = Float.parseFloat(amountField.getText());
 float driverTotal = controller.calculateCost(gasAmount, gasType);
 String driverName = nameField.getText();
 JOptionPane.showMessageDialog(null, driverName +" should pay $" + driverTotal );
 
 GasPriceModel customer = new GasPriceModel(driverName, gasAmount, gasType, driverTotal);
 
 controller.saveEntry(customer);
 }

 }
}

The View above creates a user interface using the configureView() method. It then collects data after an event occurs (through an action listener). The View above then sends the data collected to the Controller, which then performs some calculations and returns data to the View.

Executing the MVC Application

import java.awt.EventQueue;

public class App {

 public static void main(String args[]) {
 EventQueue.invokeLater(
 new Runnable() {

 @Override
 public void run() { 
 GasPriceController controller = new GasPriceController(); 
 new GasPriceView(controller); 
 }
 });
 }
}

Executing the App class above will generate the following UI:

Populating the UI with the relevant data will generate the following popup UI:

If you look at the left of the image above, you’ll see that the application also created a new file called “data.dat.” So, this MVC application collects data from a user through a UI (View), which sends that data to the Controller. The controller manipulates the data by performing some calculations, then it stores that data in a file using the Model.

Java Input and Output: A Beginner’s Guide

If you take a close look at the application created in this article, there are several apparent benefits. Some of these benefits include:

  • Scalability
  • Easier code testing
  • The creation of more concise code

But MVC architecture isn’t the only useful design pattern that can enhance your development process.