How Naked Objects works

To understand how Naked Objects works we are going to look at a simple application, a reservation system for limousine company: Executive Car Services (ECS). We shall be looking at the system from the perspective of both an end-user (in this case a call-centre booking agent) and a software developer. For the developer perspective we shall be looking at the system using a popular IDE (VisualAge). We shall not be looking at the actual Java code - but at how the structure of the software written by the developer relates to the system as seen by the user. Latter documents look at the actual coding in the form of a tutorial.

Naked object classes

Below is a basic screenshot from the ECS system, as seen by a reservations agent. On the left hand side there is a window that lists the classes of business object available to this user: Bookings, Cities and so on.

Turning to the developer's view of the project, we can see a set of Java projects. 'ECS Bookings' contains all the code for the Executive Car Services project, in three packages. The 'ecs.explore' package contains the prototype code written during the exploratory phase; 'ecs.delivery' contains the code written for the delivered system; and 'ecs.tests' contains both the unit tests and user-acceptance tests that support the development of the delivery code.

Inside the 'delivery' package package we can see a set of Java class definitions that correspond to those shown to the user.

The business system consists of nothing more than these 'naked' object definitions. There is no 'application' code sitting on top of these objects. In the list you can see a TestApp class, which is used by the developer to test the application, but which contains no business logic.

Back in the user's view we have now right-clicked on the Locations icon, which has brought up the menu of 'class methods' that are available to the user. These include the ability to create a new instance of this class and to retreive existing ones from storage. These methods are generic and automatically provided by the framework for any naked object class - the programmer does not have to write any code for this. It is possible to add class methods specific to a particular business class, for example, a method on the Bookingclass to generate an analysis of bookings over the next month . Equally it is possible to inhibit the generic methods.

In the user's view each class is represented by its own icon. The framework looks for a .gif file (within the project's images directory) with a file name corresponding to the class name. If the programmer does not provide one then a default icon will be displayed.

The title shown under each of the class icons is automatically derived from the name of the Java class, with some reformatting. Thus, the Booking class is shown as Bookings and CreditCard as Credit Cards . (If the class name is takes an irregular plural such as 'cities' or 'fish' then the programmer can specify this manually.)

Naked object instances

On the user's screen we can now also see a number of icons representing individual instances of several of the business classes, plus one 'collection' of instances (the seven cities).

Each instance has an icon to indicate which class it belongs to, and a title (e.g. Richard Pawson or Logan Airport ) to indicate what that specific instance represents. Although each object uses the same icon as its class by default, the programmer can also over-ride this, when there is good reason to do so. It would be possible, for example, to have the icon for an Employee to be a photograph of that individual employee. A more common use is to have a small number of variaints on the basic icon, to provide a visual indication of that object's status - such as a red, amber, or green background.

Notice that the New York icon appears in more than one place (i.e inside a Cities collection and on its own). These two icons are both views of the same object. What you can do through one icon, you can do through the other.

Turning to the developer's view, each class has a title method defined (the screen shows it for the City object).

Normally the title is built from one or more of the object's attributes such as the name or date. (Note: In addition to showing the name of the method (title), our IDE shows that the method will return an object of class Title.)

Right-clicking on one of the instances produces a pop-up menu. The actions at the top of this menu are generic - they are automatically generated by the framework for any naked object class. The programmer does not need to write any code for these. (We'll look at the object-specific actions at the bottom of the menu under actions ). The generic methods include the ability to view the object in a variety of different ways. Double-clicking on an object is a short-cut to the main view.

Fields

Double-clicking on the Booking instance reveals a set of labelled fields, each containing some text or an icon representing another object.

Turning to the developer's view, we can see that the fields seen by the user correspond directly to the get methods defined within the Booking class.

Each declared get method has two parts. The second part gives the method a name that programmers can use to make requests of this object (e.g. getContactTelephone ). In the user view the name of each field is just a reformatted version of the get method name (e.g. Contact Telephone ). This correspondence improves communication between the user and developer. If necessary, this automatic correspondence can be over-ridden, for example to display the field name in another language.

The first part of the method declaration defines the type of object that the field will contain, and we can recognise three kinds of construct here.

The get methods (formally called 'accessor' methods) specify the data that can be requested of it (the data, in this case, almost always takes the form of other object types). Additionally, set specify the data that can be passed to an object.

Using get and set methods (which is standard Java practice) means that whatever is accessing the data from outside the object does not need to know how that data is stored - for example it may be that the object doesn't store that data at all, but creates it dynamically each time it is asked for. Additionally, the set method will typically contain code to check that the data being passed is valid, and to ensure that the object receiving that data always remains in a valid data.

In the Naked Objects framework, these get and set methods determine the set of fields that can potentially be viewed and altered by the user.

Looking at the developer's view of the Booking object, we can see several set and get methods.

For example there is a getDropOff method and a setDropOff method, which are the two accessor methods for the dropOff variable. Both methods deal with the same type of object (a Location). The set method requires a Location to be passed in, returning nothing ( void). The get method does not require any parameters, but itself returns a Location .

To understand how these are used we need to look again at the three main uses of fields.

As these simple get and set accessors follow a standard Java pattern, some IDEs (including VisualAge) will generate them automatically from the declaration of a variable. These standard pieces of code need only be extended if you wish to add some data validation, formatting or other constraints into the methods.

It is also worth stressing here that although we have explained how the get and set methods trigger the naked object viewing mechanism to provide user capabilities such as drag and drop, these accessors are no different to the ones you would have to write for a conventional business object that did not show through to the user.

Association

We have already seen how a field with the standard accessor methods can be used to implement a simple association between two objects: a Location object knowing in which City it belongs, for example.

Oftentimes it is necessary to implement more sophisticated associations. The most common of these is when you want an association to be navigable from both directions. For example, when you open a Booking object you expect to see the Customer it is associated with. But it might also be very useful to have a field in the Customer containing a collection of all the recent Bookings made by the Customer. We therefore need to ensure that every time a Customer is associated with a Booking, then that Booking becomes associated with the Customer .

This is achieved through the use of an 'associate ' method, and a corresponding 'dissociate' method, as we can see here:

the Booking object has a method to associate a Customer. Were we to examine the Java code we would see that the first thing this method does is call the setCustomer method. Then it calls a method on the customer object to add itself (the booking) to the collection of bookings in that object. The principle here is that for any association between two objects that needs to be navigable in both directions, one of the objects is always responsible for maintaining that association and the other one delegates the task to it.

As with the simple accessors, the associate/ dissociate methods are not specifically for use by the user - they can be called by any other object or program that needs to form an association. However, when the user drags and drops an object onto a field in another object, the viewing mechanism will automatically check to see if there is an associate method and call that. If there is no associate method it will call the simple set method.

Readers may be asking why this responsibility for maintaining the bi-directional associations cannot simply be included in the set methods. The reason is that the set method is called by the persistence mechanism whenever an object is retrieved from persistence. Effectively that object is re-created using the data provided by the persistor, and fields are individually set. You only want the association code called when the association is first created.

Behaviour

In systems designed using naked objects, all business behaviours are implemented as methods on the core business objects themselves: there is no 'process' layer or other form of scripting that sits on top of the objects. If we right click on one of our business objects such as a Booking:

we see that the pop-up menu includes a number of object-specific business behaviours: in this case Check Availability , Return Booking and Confirm. As with the fields, there is a 1:1 correspondence between these menu-actions and the methods in the Java code. Turning to the developer view of Booking:

We can see that there are three methods corresponding to these menu items. In all three cases the method name is prefixed by action (e.g. actionConfirm() ). The framework's viewing mechanism uses this action prefix as a cue to make that method available to the user, stripping off the prefix and separating the words. (As with the attributes and associations, it is possible to make the method name different from the user menu name, for example to support multiple language.) However, the action prefix should not be thought of as specifically having to do with the user interface: the action methods can all be called by other objects. Think of action as merely a convention for writing business behaviours.

Any method on the Java object not preceded by action will not be available directly to the user. Such methods could only be invoked by other objects. We generally only use this to implement technical behaviours rather than business behaviours - all of which should be designed as though a user was invoking them directly, even if, in fact, they are most often called by other objects.

The actionReturnBooking() method is preceded by Booking, indicating that this method will return a Booking object. Were we to examine the Java code we would see that this method creates a brand new Booking object, copies across the Customer, Payment Method and Contact Telephone from the existing booking, and copies the Pick Up and Drop Off Locations, but swaps them over. If this method was called by another object in the system, then this new booking would be returned to that object, which would be expecting to do something with it. If, however, the method had been called by the user selecting Return Booking... on the pop-up menu, then the returned object would be returned to the viewing mechanism and appear as a new window on the user's screen. (The ellipsis (...) on the menu option is an indicator to the user that this action will return something, and is, again, auto-generated by the viewing mechanism).

The other two action methods, CheckAvailability and Confirm, are both preceded by void indicating that they do not return an object. The result of these methods will usually be a change to the state of the object (meaning a change to one or more of the fields) - although they could also invoke methods on other associated objects.

Now lets look at a slightly different kind of action method, this time on the Location object. Looking first at the developer's view:

we can see a method called actionNewBooking . This method takes a Location object as a parameter, meaning that when the method is called on a particular Location object, another Location object must be supplied as an argument. (The previous three examples of actionMethods were all 'zero parameter' methods). The purpose of this particular method is to allow a new booking to be created directly from two Location objects, representing the pick-up and drop-off locations.

The user invokes this method simply by dragging one Location object onto another. Usually this would be done within a list of Locations: either a list of the most popular Locations within a City (such as airports and theatres), or Locations that are specific to an individual customer such as their home and office.

Abouts

The above methods we have just looked at should not always be available. For example, in the Booking shown above, the Confirm option was greyed-out, because not all of the necessary information had been specified within the Booking at that point.

These methods, and other aspects of Naked Objects, can be controlled by adding about methods that correspond to the method we need to control. The about method must return an About object that contains a name, description and permissions. These permissions determine whether the user is able to access the controlled entity and whether it is currently available to be used.

In our example the Confirm option is greyed out because the aboutActionConfirm method, which corresponds to the actionConfirm method, returned an About object that vetoed the action with the object in it current state. The viewer checks this About object before offering the options on the popup menu and determines how to display the action. After all the information has been entered within the Booking, a subsequent look at the menu will show that this option is now enabled.

It is worth noting that if no about method is declared then an action will always be allowed.