Tuesday, August 25, 2009

Simple Swing App - The Model

For this post, I just want to cover the model portion of the application. The next post will concentrate on the view, and then I will finally go over the libraries used within the application (SwingX, EventBus, etc.).
To help facilitate developing models, I have a class that all my models will extend. This class is Model.java, and it really does nothing except allow for any type of PropertyChangeListener registration as well as all methods to fire property change notifications.

Here is a snippet of the class:


public abstract class Model {

private PropertyChangeSupport _support;
private VetoableChangeSupport _vetoable;

/** Creates a new instance of Model */
public Model() {
_support = new PropertyChangeSupport(this);
_vetoable = new VetoableChangeSupport(this);
}

The rest of the methods are just pass through methods for all the methods found in the two XXXSupport classes. Pretty simple stuff.

That is it for the framework portion of the model. Now, the application's model is composed of two classes. The first class just models a contact/user, and it is called MyUser.java. It has the typical getters and setters for the user attributes I am modeling. The setter methods also fire PropertyChangeEvents whenever they are called. Here is a portion of this class:


public class MyUser extends Model implements Comparable<MyUser> {

public static final String FIRST_NAME_PROP = "MyModel.FirstName";
public static final String LAST_NAME_PROP = "MyModel.LastName";
public static final String SSN_PROP = "MyModel.SocialSecurityNumber";
public static final String BIRTHDAY_PROP = "MyModel.Birthday";
public static final String IMAGE_PROP = "MyModel.Image";

private String firstName;
private String lastName;
private String ssn;
private Date birthday;
private Image image;

/**
*
*/
public MyUser() {
this("John", "Doe", "000-00-0000", new Date(), null);
}

/**
*
* @param first
* @param last
* @param ssn
* @param birth
*/
public MyUser(String first, String last,
String ssn, Date birth) {
this(first, last, ssn, birth, null);
}

/**
*
* @param first
* @param last
* @param ssn
* @param birth
* @param image
*/
public MyUser(String first, String last,
String ssn, Date birth, Image image) {
super();
setFirstName(first);
setLastName(last);
setSocialSecurityNumber(ssn);
setBirthday(birth);
setImage(image);
}


This just shows the property names used when firing events and the constructors for creating a MyUser. Here is a typical getter and setter:


/**
* @return the firstName
*/
public String getFirstName() {
return firstName;
}

/**
* @param firstName the firstName to set
*/
public void setFirstName(String firstName) {
String oldValue = this.firstName;
this.firstName = firstName;
this.firePropertyChange(
FIRST_NAME_PROP, oldValue, this.firstName);
}


All of this is simple JavaBean specification coding.


I discovered a very cool feature in NetBeans when creating this class. After I completed all the getters/setters, I was poking around by right-clicking in the source editor and selecting "Insert Code...". One of the options was to override the equals and hashCode methods. I selected this because I thought it would be a good thing to do and not only did the methods show up, but they were completely implemented as well. Very nice, and saved me from looking up the proper ways to override these methods in the great Effective Java book.

Finally, the last class to be covered is MyContactsModel.java. Please don't comment on how incredibly descriptive my names are. This class is the actual model that gets wired to the view. It basically holds a List of MyUser objects, and has methods that operate on this list of users (as well as a settable Comparator for sorting).

Here is the constructors for the class:


public class MyContactsModel extends Model {

public static final String USER_MODIFIED_PROP = "MyContactsModel.UserModified";
public static final String USER_ADDED_PROP = "MyContactsModel.UserAdded";
public static final String USER_DELETED_PROP = "MyContactsModel.UserDeleted";
private static final Comparator COMPARATOR = new UserAgeComparator();

private final int[] LOCK = new int[0];
private Comparator _comparator;
private List<MyUser> _contacts;

/**
*
*/
public MyContactsModel() {
this(new ArrayList<MyUser>());
}

/**
*
* @param contacts
*/
public MyContactsModel(List<MyUser> contacts) {
super();
this._contacts = new ArrayList<MyUser>();
this._contacts.addAll(contacts);
Collections.sort(_contacts, (_comparator == null ? COMPARATOR : _comparator));
}

/**
*
* @param comparator
*/
public void setComparator(Comparator comparator) {
this._comparator = comparator;
Collections.sort(_contacts, (_comparator == null ? COMPARATOR : _comparator));
}


The methods used for operating on the list are:
  • public boolean addUser(MyUser user)
  • public boolean removeUser(MyUser user)
  • public boolean modifyUser(MyUser original, MyUser changed)


There is also the following for getting the data:

  • public List getContacts()


The operations on the model also fire PropertyChangeEvents. Here is the addUser method:


public boolean addUser(MyUser user) {
boolean added = true;

synchronized (LOCK) {
if (_contacts.contains(user) || user == null) {
return false;
}
_contacts.add(user);
Collections.sort(_contacts, (_comparator == null ? COMPARATOR : _comparator));
}
this.firePropertyChange(USER_ADDED_PROP, null, user);

return added;
}

That is it for the model portion. The code is really very simple (and partially written by NetBeans). Next we will look at the actual UI creation and how it interacts with the model. Again, the UI makes use of a framework class to help facilitate the MVC design. Just to keep from losing the focus: all these framework pieces are important because we want to see how it affects the porting of the application to the NetBeans Platform. Have patience, we'll get there soon enough.

No comments:

Post a Comment