dotuseful Java library

About
License

Documentation

Articles

Post-MVC

Download
Forums
.useful Team
Contribute

Hosted by

SourceForge.net Logo

Post-MVC

An interesting idea has come into my mind. We all play with MVC and its variations where we have Model and UserInterface so we end up with code like

public class AlbumController {
      //...
      protected void updateModel() {
            AlbumView1 view = getView();
            AlbumModel1 model = getModel();
            model.setTitle(view.getTitle());
            model.setArtist(view.getArtist());
            model.setClassical(view.isClassical());
            model.setComposer(view.getComposer());
      }
      //...
}

This is reasonably if we want Model to know nothing about Views.

But I find myself very comfortable with another idea where an object is responsible for its own updates and won't let anyone else to change it. The object should change itself only when it decides to. When I see code like

model.setTitle(view.getTitle());
model.setArtist(view.getArtist());
model.setClassical(view.isClassical());
model.setComposer(view.getComposer());

I see that AlbumController takes too much care on model spending too much updating it. I feel that the code really should belong to model. Definitely, what we have here is code smell called inappropriate intimacy - http://wiki.java.net/bin/view/People/SmellsToRefactorings

So I come with idea to move this update() code to my Model. At the same time I still want to keep Model separated from Views.

Now let's take a closer look at our View. Let's suppose we model some kind of music album store. We have AlbumModel class which is the actual Model of our Album, and we have AlbumView class which is visual representation of our Album model.

Can you see something pretty similar between our View and Model? Our AlbumView contain several text fields like title , artist , composer and such which correspond to fields in our Album class. But with all these fields, we can agree that our AlbumView contain some kind of model of Album ! Pretty unusual is it? So we are absolutely able to extract some Album interface from both AlbumModel and AlbumView

public interface Album {
  String getTitle();

  String getArtist();

  Boolean isClassical();

  String getComposer();
}

and make AlbumView implements Album interface

public class AlbumView2 implements Album {
// everything else stays the same!

Now we can move updateModel() ( http://www.refactoring.com/catalog/moveMethod.html ) from AlbumController to AlbumModel while staying no way connected to AlbumView

public class AlbumModel2 implements Album {
private String title;

private String artist;

private boolean classical;

private String composer;

public String getTitle() {
return title;
}

public String getArtist() {
return artist;
}

public boolean isClassical() {
return classical;
}

public String getComposer() {
return composer;
}

public void update(Album model) {
title = model.getTitle();
artist = model.getArtist();
classical = model.isClassical();
composer = model.getComposer();
fireModelChanged();
}

protected void fireModelChanged() {
// ...
}
}
public class AlbumController2 {
private AlbumView2 view;

private AlbumModel2 album;

protected void updateModel() {
AlbumView2 view = getView();
AlbumModel2 model = getModel();
model.update(view);
}

// ...

private AlbumView2 getView() {
return view;
}

private AlbumModel2 getModel() {
return album;
}

}

Now let's take a look at what we had before and what we have now.

Advantages

Let's suppose you have

public class AlbumController {
      //...
      protected void updateModel() {
            AlbumView1 view = getView();
            AlbumModel1 model = getModel();
            model.setTitle(view.getTitle());
            model.setArtist(view.getArtist());
            model.setClassical(view.isClassical());
            model.setComposer(view.getComposer());
      }
      //...
}

This way your model gets updated four times. Four times the model will fire StateChanged event. This could be time consuming. You will also find it unacceptable when you need to do an update in one call to wrap it in a transaction.

Compare it with

public class AlbumController2 {
  private AlbumView2 view;

  private AlbumModel2 album;

  protected void updateModel() {
    AlbumView2 view = getView();
    AlbumModel2 model = getModel();
    model.update(view);
  }

where the model gets updated only once.

Let's suppose you will go further and try to update your model with one call to some model.setState(newState). You create some class, fill it with data from View and pass it to Model. You need to:
- declare new class;
- instantiate it;
- fill it with data fetched from the View;
- call Model method with new data as parameter;
- your Model will fetch data from given parameter, set its fields and fire stateChanged event.

Class AlbutModelData {
  String title;
  ...
  String getTitle() {
  ...
  }
  void setTitle(String newTitle) {
  ...
  }
}
 
class Controller { 
  // ****** The action starts here
   public void okPressed() { 
       // Step 1 - create new object 
       AlbutModelData newModelData= new AlbutModelData(); 
       // 2 - fill it with data entered by the user 
       newModelData.setTitle(getView().getTitle());
       ...
       // 3 - notify albumModel with new data 
      getModel().updateState(newModelData) 
   } 
 
//Album Model 
class AlbumModel { 
   public void updateState(AlbutModelData newModelData) { 
       // We are not finished, we still need to 
       // 4 - fetch new state from newModelData 
       title = newModelData.getTitle(); 
       ... 
       // 5  fire change event.
       fireModelChanged(); 
       ... 
   } 
} 

Now an improved code

interface Album {
  String getTitle();
  String getComposer();
  ...
}
 
class Controller { 
  // ****** The action starts here
   public void okPressed() { 
       // Step 1 - controller notifies model
       getModel().update(getView());
   } 
 
//Album Model 
class AlbumModel implements Album { 
   public void update(AlbutModel newModel) { 
       // 2 - fetch new state from newModel
       title = newModel.getTitle(); 
       ... 
       // 3  fire change event. This was step (2) before.
       fireModelChanged();
   }
} 

We did a good job having simplified the code while didn't introduce new dependencies.

Now take a look at part of our Controller

class Controller { 
  // ****** The action starts here
   public void okPressed() { 
       // Step 1 - controller notifies model
       getModel().update(getView());
   } 

Questions

Will it work for complex situations?

Let's suppose we need to create solution with role-based restrictions for viewing and updating our Model. Let's suppose we have users with Reader, Author, Editor and Manager roles. Reader can read album records. Author is allowed only to view and edit album records created by its own. Editor have access to all records. Manager is able to view / change some hidden fields like LastEdited or AccessList.

Main problem here is that you might end up with a view which is hardly to implement model interface because it just miss some fields. Messaging a set of setXXX() methods on your model is not an option because you want to wrap a change into single transaction. So you might end up with update(param1, param2, ...) method. Replacing a parameter list with parameter object we have update(SomeDataSet paramObject). Here is still a place for improvement. Instead of creating paramObject, we can extract a corresponding interface from our View which will be a subset of our Model interface, and invoke update(PartialInterface viewInstance) on our Model.

Have thoughts? We want to hear from you! Contact us on our forums.