title: Model-View-Presenter passive view: bootstraping - who displays the view initially?
body: <p>In the Passive View Model View Presenter pattern, who has the responsibility for displaying the view? I have found related answers for other MVP versions, but they don't seem applicable to the passive view version.</p>
  
  <p>I have a concrete example using Java Swing. It's pretty simple, but basically we have a <code>SwingCustomersView</code> which internally builds a JPanel with a table (list of customers) and a label displaying the currently selected customers age. When a customer is selected in the table, the presenter retrieves the selected customer age from the model. I think the example is a correct implementation of MVP Passive View, but correct me if I'm wrong.</p>
  
  <p>The question is how do we bootstrap these classes? For example, if we wanted to display the <code>SwingCustomersView</code> in a JFrame. How would one do that? I imagine something along the lines of:</p>
  
  <pre><code>void launcher() {
      CustomersModel model = new CustomersModel();
      SwingCustomersView view = new SwingCustomersView();
      CustomersPresenter presenter = new CustomersPresenter(view, model);
  }
  </code></pre>
  
  <p>This is the initial wiring, but nothing is displayed yet. How do we actually display the view? Is it the responsibility of (1) <code>launcher()</code> , (2) <code>SwingCustomersView</code> or (3) <code>CustomersPresenter</code> to display the view? Unfortunately I don't believe any of those are very good as you can see from my thoughts below. Perhaps there's another way?</p>
  
  <h3>(1.a): launcher</h3>
  
  <p>Make <code>SwingCustomersView</code> extend JFrame and make it add it's internal JPanel to the content pane of itself. Then we can do this:</p>
  
  <pre><code>void launcher() {
      CustomersModel model = new CustomersModel();
      SwingCustomersView view = new SwingCustomersView();
      CustomersPresenter presenter = new CustomersPresenter(view, model);
      view.setVisible(true); // Displays the view
  }
  </code></pre>
  
  <p>However in this case we don't use the <code>presenter</code> instance for anything. Isn't that strange? It's just there for wiring, we could just as well delete the variable and just do <code>new CustomersPresenter(view, model)</code>.</p>
  
  <h3>(2): SwingCustomersView</h3>
  
  <p>Make <code>SwingCustomersView</code> take a <code>Container</code> in the constructor to which it should add it's internal JPanel:</p>
  
  <pre><code>void launcher() {
      CustomersModel model = new CustomersModel();
      JFrame frame = new JFrame("Some title");
      SwingCustomersView view = new SwingCustomersView(frame.getContentPane());
      CustomersPresenter presenter = new CustomersPresenter(view, model);
      frame.pack(); 
      frame.setVisible(true) // Displays the view
  }
  </code></pre>
  
  <p>However, same problem as (1): the <code>presenter</code> instance does nothing. It seems strange. Furthermore with both (1) and (2) it is possible to display the view before the presenter is hooked up, which I imagine could cause strange results in some situations.</p>
  
  <h3>(3): CustomersPresenter</h3>
  
  <p>Make <code>CustomersPresenter</code> responsible for displaying the view somwhow. Then we could do this:</p>
  
  <pre><code>void launcher() {
      CustomersModel model = new CustomersModel();
      SwingCustomersView view = new SwingCustomersView();
      CustomersPresenter presenter = new CustomersPresenter(view, model);
      presenter.show() // Displays the view
  }
  </code></pre>
  
  <p>This would solve the problem of not using it for anything after construction. But I don't see how do to this without either changing the <code>CustomersView</code> interface or making <code>CustomersPresenter</code> too dependent on the underlying GUI implementation. Furthermore, displaying a view doesn't sound like presentation logic and thus doesn't seem to belong in the presenter.</p>
  
  <h1>Example</h1>
  
  <pre><code>public class CustomersModel {
      private List&lt;Customer&gt; customers;
  
      public CustomersModel() {
          customers = new ArrayList&lt;Customer&gt;();
          customers.add(new Customer("SomeCustomer", "31"));
          customers.add(new Customer("SomeCustomer", "32"));
      }
  
      public List&lt;Customer&gt; getCustomers() {
          return customers;
      }
  }
  
  public class Customer {
      public String name;
      public String age;
  
      public Customer(String name, String age) {
          this.name = name;
          this.age = age;
      }
  }
  
  public interface CustomersView {
      void addCustomerSelectionChangeListener(ItemListener listener);
      void onNewActiveCustomer(String age);
      void onNewCustomers(List&lt;String&gt; newCustomers);
  }
  
  public class SwingCustomersView implements CustomersView {
      // Swing components here all put into a main JPanel
  
      public void addCustomerSelectionChangeListener(ItemListener listener) {
         // Add event listener to table
      }
  
      public void onNewActiveCustomer(String age) {
          // Display age in label beneath table
      }
  
      public void onNewCustomers(List&lt;String&gt; newCustomers) {
          // Display customers in table
      }
  }
  
  public class CustomersPresenter {
      private final CustomersView view;
      private final CustomersModel model;
  
      public CustomersPresenter(CustomersView view, CustomersModel model) {
          this.view = view;
          this.model = model;
          initPresentationLogic();
          populateView();
      }
  
      private void initPresentationLogic() {
          view.addCustomerSelectionChangeListener(new ItemListener() {
              @Override
              public void itemStateChanged(ItemEvent e) {
                  String selectedName = (String)e.getItem();
                  List&lt;Customer&gt; customers = model.getCustomers();
                  for (Customer c : customers)
                      if (c.name.equals(selectedName))
                          view.onNewActiveCustomer(c.age);
              }
          });
      }
  
      private void populateView() {
          List&lt;Customer&gt; customers = model.getCustomers();
          List&lt;String&gt; names = new ArrayList&lt;String&gt;();
          for (Customer c : customers)
              names.add(c.name);
  
          // View will now populate its table, which in turn will call customerSelectionChangeListener
          // so the view 'automagically' updates the selected contact age too
          view.onNewCustomers(names);
      }
  }
  </code></pre>