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) {
// ...
}
}