- Published on
CS 3500 Day 7
- Authors
- Name
- Jacob Aronoff
Object Oriented Design
Today we're moving onto controllers, the C in MVC.
The controller takes input from the user and decides what to do.
Controllers:
- Glue of the system
- Controls how and when the model is used
- Controls what must be shown to the view and when (in some cases)
- Controls what action must be taken when user interacts with system (in some cases)
- Controls the sequence of operations in an application(in some cases)
The view should NEVER talk directly to the model (and vice versa). The controller is the middle man.
MVC Pattern:
- Model: Offers actual operations
- Oblivious to when they are needed and how to present results
- View: Presents results
- Oblivious to how they are produced or what to do next
- Controller: Delegates to model and view
- Oblivious to how model completes the operations or how specifically the view shows output
Our next assignment is going to be the controller of Freecell. Our FreecellController looks like this:
FreeCellController:
- “Controls” the game
- Uses the model and the view in specific sequence
- Determines when to ask for user input
- Determines when to use which operation of model
- Determines when to show output to the view
- The sequence of the game is determined by the controller, not the user
Synchronous Controllers
- Determines the sequence of operations of the system
- Determines when and how the system interacts with something external
- Suitable for pre-baked “rules-based” applications, like games
- Challenges:
- How to truly separate controller from view so each one is replacable?
- What to do when system is reactive in nature (to user input)?
- User interaction decides program behavior, not controller
- Examples: Microsoft Word, IntelliJ
Synchronicity happens like 1->2->3->4. There's an order to events. Synchronous tells the user to do something and then gets input. Asynch gets input and does something.
Asynchronous Controllers
- Controller gets control when external input is given
- Controller methods are called as a response to external input
- Such methods in the controller are called callbacks
- GUI programs typically work this way
- User clicks a button, moves the mouse ⇒ a controller method is called
- In OO GUIs, callbacks are often wrapped in classes called listeners
- Look at MVCExample code
In most Java projects, the main method creates everything. For example:
public class MainRunner {
public static void main(String[] args) {
IModel theModel = makeAModel();
IView aView = makeAView();
IController theController = makeController(theModel, aView);
theController.go();
}
}
How do we show output? The simplest way is to just use System.out.print. To get input we use a Scanner. Now we're going an in class example.
public class SimpleCalc1 {
public static void main(String[] args) {
int num1, num2;
Scanner scan = new Scanner(System.in);
num1 = scan.nextInt();
num2 = scan.nextInt();
System.out.printf("%d", num1 + num2);
}
}
Let's turn this into an MVC example:
public class SimpleCalc2 {
public static void main(String[] args) {
int num1, num2;
Scanner scan = new Scanner(System.in);
num1 = scan.nextInt();
num2 = scan.nextInt();
System.out.printf("%d", new Calculator().add(num1, num2));
}
}
class Calculator {
public int add(int num1, int num2) {
return num1 + num2;
}
}
Let's add a controller:
public class SimpleCalc1 {
public static void main(String[] args) {
Calculator model = new Calculator();
CalcController controller = new CalcController(model);
controller.go();
}
}
class CalcController {
private final Calculator model;
public CalcController(Calculator model){
this.model = model;
}
public void go(){
int num1, num2;
Scanner scan = new Scanner(System.in);
System.out.println("Enter a number: ");
num1 = scan.nextInt();
System.out.println("Enter another number: ");
num2 = scan.nextInt();
System.out.printf("The answer is: %d", model.add(num1, num2));
}
}
class Calculator {
public int add(int num1, int num2){
return num1+num2;
}
}
Now we're running into issues with testing. How do you test something that takes input and output? We need to set a System.in and a System.out. In order to make this work we add an input stream and output stream property to our class:
class CalcController {
private final Calculator model;
private InputStream input;
private OutputStream output;
public CalcController(Calculator model) {
this.model = model;
this.input = System.in;
this.output = System.out;
}
public CalcController(Calculator model, InputStream input, OutputStream output) {
this.model = model;
this.input = input;
this.output = output;
}
public void go() {
int num1, num2;
Scanner scan = new Scanner(input);
output.println("Enter a number: ");
num1 = scan.nextInt();
output.println("Enter another number: ");
num2 = scan.nextInt();
output.printf("The answer is: %d", model.add(num1, num2));
}
}
Now for the test:
public class CalcControllerTest {
@Test
public void go() throws Exception {
Calculator model = new Calculator();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(baos);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream("6\n 8\n".getBytes());
CalcController controller = new CalcController(model, byteArrayInputStream, printStream);
controller.go();
assertEquals(baos.toString(), "Enter a number: \n"
+ "Enter another number: \n"
+ "The answer is: 14");
}
}