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:

The view should NEVER talk directly to the model (and vice versa). The controller is the middle man.

MVC Pattern:

Our next assignment is going to be the controller of Freecell. Our FreecellController looks like this:

FreeCellController:

Synchronous Controllers

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

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");
  }

}