The Artima Developer Community
Sponsored Link

Guideline 4
Interface Design by Bill Venners
Use Messengers to transmit information


Interface Design | Contents | Previous | Next

Guideline 2 encourages you to think of objects of bundles of services, not bundles of data. This guideline irreverently suggests that sometimes its OK to design objects that are bundles of data.

On occasion, you will see objects that are nothing more than containers for data. I like to call such objects Messengers. A messenger allows you to package and send bundles of data. Often the data is passed to the messenger's constructor, and the messenger is sent along its way. Recipients of the messenger access the data via get methods. Messengers are usually short-lived objects. Once a recipient retrieves the information contained in a messenger, it usually kills the messenger (even if the news is good).

In general, you should move code to data as described in Guideline 1. Most of your object designs should be service-oriented objects, as described in Guideline 2. But on occasion, you may find yourself with some data that you don't know what to do with. Sometimes you know some information, but you don't know what behavior that information implies. You can't move the code to the data, because even though you have the data, you don't know what the code should do. In such cases, you can encapsulate the data inside a messenger object, and send the messenger to some recipient that does know the behavior implied by the data. The recipient extracts the data from the messenger and takes appropriate action.

One common example of messengers is exceptions. As mentioned in Guideline ?, exception objects are usually composed of little more a small amount of data (if any), which is passed to the constructor, and some access methods to let catch clauses get at that data. The primary information in an exception is carried in the name of the exception itself.

 1 package com.artima.examples.account.ex1;
 3 /**
 4 * Exception thrown by <code>Account</code>s to indicate that
 5 * a requested withdrawal has failed because of insufficient funds.
 6 */
 7 public class InsufficientFundsException
 8     extends Exception {
10     /**
11     * Minimum additional balance required for the requested
12     * withdrawal to succeed.
13     */
14     private long shortfall;
16     /**
17     * Constructs an <code>InsufficientFundsException</code> with
18     * the passed shortfall and no specified detail message.
19     *
20     * @param shortfall the amount in excess of available funds
21     *    that caused a withdrawal request to fail.
22     */
23     public InsufficientFundsException(long shortfall) {
24         this.shortfall = shortfall;
25     }
27     /**
28     * Constructs an <code>InsufficientFundsException</code> with
29     * the passed detail message and shortfall.
30     *
31     * @param message the detail message
32     * @param shortfall the amount in excess of available funds
33     *    that caused a withdrawal request to fail.
34     */
35     public InsufficientFundsException(String message, long shortfall) {
36         super(message);
37         this.shortfall = shortfall;
38     }
40     /**
41     * Returns the shortfall that caused a withrawal request
42     * to fail. The shortfall is the minimum additional balance
43     * required for the requested withdrawal to succeed.
44     *
45     * @returns shortfall the amount in excess of available funds
46     *    that caused a withdrawal request to fail.
47     */
48     public long getShortfall() {
49         return shortfall;
50     }
51 }

Another example of the Messenger are events. Like exceptions, event objects often just encapsulate some data, which is passed to the constructor, and offers access methods to let listeners get at the data. For examples of this see the Event Generator idiom.

Like exceptions and events, multivalued return objects are Messengers. It has some data, which must be passed to the constructor, and offers access methods so the calling method can get at the returned data.

Messengers are usually immutable (but not always: AWT event can be consumed)

In parting, I want to warn you to be suspicious of messengers when they appear in your designs. Challenge their existence. A messenger makes sense when you don't know the behavior that should result accompany some data. If you do know the behavior, then you know the code that should use that data. In this case, you should refactor. You should move the code to the data, which will transform the messenger into a service-oriented object. This is, in fact, the very process demonstrated in Guideline 2: The Matrix of Listing 2-1 was a messenger, which was transformed into a service-oriented Matrix in Listing 2-3. To get from Listing 2-1 to Listing 2-3, I moved the code for matrix addition, subtraction, multiplication, conversion to string, etc., to the Matrix class that contained the matrix data.

Probably mention the attribute classes in the Service UI API, and talk about EJB Blueprints "value" objects. Or perhaps value objects belong in Immutable.

Sponsored Links

Copyright © 1996-2018 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use