views:

178

answers:

3

I'd like to pair a Model with it's View through an interface. I want to control when and how often the view is updated. So something like PropertyChangeListener wouldn't work well (where an event is fired after each property is set).

I'm not developing for a specific GUI framework. The goal here is the ability to swap out different GUI front ends (right now for testing, but might be useful later for different versions of the app). These might be Swing, or it might be a web browser (via GWT, for example).

Below is my approach. The view implements an interface to provide a method to update. This is triggered by the controller when it determines it's done updating the model. This still feels ok to me, since the Controller is only interacting with the view through the model, the controller is not dependent on a particular implementation of the View.

So, I guess my question(s) are

  • does this work well?
  • Is this standard practice?
  • Does this pattern have a name?

Rough code sample (Java):

// Controller, manages Items (the model)
class ItemList {

   void addItem(Item item) {
   }

   void doStuffWithItems() {

     // perform some set of operations, such as sorting or layout
     for (Item item : items) {
       // ....
     }

     // now with everything in it's final position:
     for (Item item : items) {
       item.updateView();
     }
   }
}

// Model
class Item {
  private int top;
  private int left;
  private int width;
  private int height;

  // Can remember it's previous position/size:
  public void savePostion() {
  }

  // And recall it for the Controller to use:
  public public Position getSavedPosition() {
  }

  // Plus some other useful functions:
  public boolean intersectsWith(Item other) {

  }

  public void updateView() {
    this.view.update();
  }

  void setView(ItemView view) {
    this.view = view;
  } 
}

// Interface used by View implementations
public interface ItemView {
  // Trigger the view to reflect the current state of the model
  void update();
}

// Example, as a Swing component
class ItemComponent extends JComponent implements ItemView {
  private Item item;

  public ItemComponent(Item item) {
    this.item = item;
    item.setView(this);
  }

  // ItemView#update
  public void update() {
    // update the component's size/position
    setBounds(new Rectangle(item.getLeft(), item.getTop(), item.getWidth(), item.getHeight()));
  }

  @Override
  public void paint(Graphics g) {
    // ...
  }
}
+1  A: 

I would avoid forcing the View to implement an interface only for change notification. Create a separate "update now" event on the model instead.

David Schmitt
A: 

The model should not be controlling or know about the view directly. The view should register a callback with the controller so the controller can tell the view when to update, that's why its the controller. You could have the model allow external listeners for a modelChangedEvent. Then the view could register with the model in that respect without the model knowing there was a view. See the J2EE blueprint for MVC and how there is an indirect event notification of state change in the model.

John Ellinwood
A: 

For traditional applications that run on the desktop of a computer I recommend variants of the Passive View. The class responsible for creating and managing the form is a thin shell that passes events to the UI Object. The UI_Object interact with the form via a interface. In term the UI Object implements a UI_View Interface and registers itself with a View Controller that is situated lower in the object hierarchy.

The UI_Object then execute object implementing the Command Pattern which modifies the model. The command object can interacts with the various views via the interfaces exposed by the View Control.

What this does is allow you to rip off the form classes and replace them with stub classes that implement the form interfaces. The stub classes are used for automated testing especially for integration tests.

The interfaces precisely define the interaction between the Form, the UI_Object, Commands and the views. They can be designed to be relatively language agnostic so they can make porting between platform easier.

What you are missing in your example are command objects. You need this structure

  • ItemViewForms
  • ItemViewImplementation
  • ItemViewFormInterface
  • ItemViewCommands
  • ItemViewInterface
  • MyModel

Incorporate ItemList in the ItemViewImplementation

ItemComponent would register with the ItemViewImplementation using the ItemViewInterface.

The sequence of events would look something like this

  • User wants to update the Item
  • Clicks on the UI (assuming that UI involves clicking with a mouse)
  • The Form tells the ItemViewImplementation through the ItemViewInterface that X has been done with Y parameters.
  • The ItemViewImplementation then creates a command object with the parameters it needs from Y.
  • The Command Object take the Y Parameters modifies the model and then tells the
  • ItemViewImplementation through the ItemViewInterface to update the UI.
  • The ItemViewImplementation tells the ItemViewForms to update the UI through the ItemViewFormInterface.
  • The ItemViewForms updates.

The advantage of this approach is that the interaction of each layer is precisely defined through interfaces. The Software ACTIONS are localized into the command objects. The Form layers is focused on display the result. The View layer is responsible for routing actions and response between the Commands and Forms. The Commands are the only things modifying the model. Also you have the advantage of ripping off the Forms Implementation to substitute any UI you want including mock object for unit testing.

RS Conley