MVC Architecture
When following the Model-View-Controller (MVC) architecture, you divide your code into three parts:
- Model - stores data, performs calculations
- View - handles user input and output
- Controller - controls the flow of the program
In this organization, the Model and View components never communicate. Instead, the
Controller gets input from the View and gives it to the Model. Then it gets results from the
Model and gives them to the View to display.
In larger programs, the Model, View, and Controller component will likely be several classes
each. However, in our first examples, we will use one class for each component.
MVC Example
In this section, we will look at a first example that applies the MVC architecture.
Suppose we want to write a program that determines whether a number is
divisible by nine. Numbers are divisible by nine if the sum of their digits are divisible by nine.
We will write this program using MVC architecture. We will also allow the user to check
whether 10 different numbers are divisible by 9.
Below is a list of the classes we’ll need, and which methods and fields will go there.
It is a good idea to make a plan like this before you start writing any code.
IO (View component)
Scanner field/constructor to initialize
public int getNum()
public void displayDivisible(int num, boolean divisible)
Calculator (Model component)
public boolean getDivisible(int num)
Proj (Controller component)
- Single
main method that will call back and forth between IO and Calculator
MVC Implementation
Now, here’s the implementation of each class:
//In IO.cs
import java.util.*;
public class IO
{
private Scanner s;
public IO()
{
s = new Scanner(System.in);
}
public int getNum()
{
System.out.print("Enter a positive integer: ");
return s.nextInt();
}
public void displayDivisible(int num, boolean divisible)
{
System.out.printf("%d is ", num);
if (!divisible) System.out.print("not ");
System.out.println("divisible by 9.");
}
}
//In Calculator.cs
public class Calculator
{
public boolean getDivisible(int num)
{
int sum = 0;
while (num != 0)
{
int digit = num%10;
num = num/10;
sum += digit;
}
if (sum % 9 == 0) return true;
else return false;
}
}
//In Proj.cs
public class Proj
{
public static void main(String[] args)
{
//Create IO, Calculator objects
IO io = new IO();
Calculator calc = new Calculator();
//Test 10 different numbers
for (int i = 0; i < 10; i++)
{
//Get input number
int num = io.getNum();
//Get divisibility
boolean div = calc.getDivisible(num);
//Display results
io.displayDivisible(num, div);
}
}
}
The first thing you probably noticed on this example is that it is significantly more code than a
single-class implementation would be. And you’re absolutely right – for this example, would make much
more sense to just use a single class. However, as your programs get bigger, you will need to
divide them up like this to be able to keep track of what’s going on. This example illustrates
how to break things into several classes so that you’ll know how when you do get a big project.
Connect 4 with MVC
In this section, we will use the Model-View-Controller architecture to implement a Connect
Four game. Again, we will first divide this game into model, view, and controller components,
and then implement each piece:
IO (View component)
Scanner field/constructor to initialize
public void printBoard(String board)
public int getMove(char piece)
public void printResults(String msg)
Board (Model component)
char[][] field/constructor to initialize
public boolean move(int column, char piece)
public boolean full()
public String toString()
public boolean winner(char piece)
ConnectFour (Controller component)
- Single
main method – call back and forth between IO and Board
Connect 4 implementation
Here’s the implementation of each class:
import java.util.*;
public class IO
{
private Scanner s;
public IO()
{
s = new Scanner(System.in);
}
public void printBoard(String board)
{
System.out.println("\nCurrent board:\n");
System.out.println(board);
System.out.println();
}
public int getMove(char piece)
{
System.out.printf("User %c, enter a column: ", piece);
return s.nextInt();
}
public void printResults(String msg)
{
System.out.printf("%s%n%n", msg;
}
}
public class Board
{
private char[][] board;
public Board()
{
board = new char[6][7];
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 7; j++)
{
board[i][j] = '_';
}
}
}
public boolean move(int column, char piece)
{
if (column < 0 || column > 6)
{
return false;
}
else if (board[0][column] != '_')
{
return false;
}
else
{
int i;
for (i = 5; i>=0 && board[i][column] != '_'; i--)
{
board[i][column] = piece;
}
}
}
public boolean full()
{
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 7; j++)
{
if (board[i][j] == '_') return false;
}
}
return true;
}
//NOTE: a StringBuilder would be much more efficient
public String toString()
{
String result = "";
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 7; j++)
{
result += board[i][j] + " ";
}
result += "\n";
}
return result;
}
public boolean winner(char piece)
{
//check row win
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 3; j++)
{
int x;
for(x = 0; x < 4; x++)
{
if (board[i][j+x] != piece) break;
}
if (x == 4) return true;
}
}
//check column win
for (int j = 0; j < 7; j++)
{
for (int i = 0; i < 2; i++)
{
int x;
for (x = 0; x < 4; x++)
{
if (board[i+x][j] != piece) break;
}
if (x == 4) return true;
}
}
//check / diagonals
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
int x;
for (x = 0; x < 4; x++)
{
if (board[i+x][j+3-x] != piece) break;
}
if (x == 4) return true;
}
}
//check \ diagonals
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
int x;
for (x = 0; x < 4; x++)
{
if (board[i+x][j+x] != piece) break;
}
if (x == 4) return true;
}
}
return false;
}
}
public class ConnectFour
{
public static void main(String[] args)
{
IO io = new IO();
Board b = new Board();
char piece = 'X';
io.printBoard(b.toString());
while (b.full() == false)
{
int col = io.getMove(piece);
boolean worked = b.move(col, piece);
if (worked)
{
io.printBoard(b.toString());
if (b.winner(piece) == true)
{
io.printResults(piece + " wins!");
//this will leave the program
return;
}
//switch the turn
if (piece == 'X') piece = 'O';
else piece = 'X';
}
else
{
io.printResults("Invalid move");
}
}
//we would have quit the program if someone had won
io.printResults("Tie game");
}
}