Published on

CS 3500 Day 7

Authors
  • avatar
    Name
    Jacob Aronoff
    Twitter

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

}