Software Development Magazine

Implementing an Object-Oriented Order Screen

To successfully plot your organization's development solutions, you need to know how to separate business behavior from the user interface.

by Scott Ambler
Reprinted from Software Development Magazine

This month, I'll describe a design for implementing an order entry screen, the prototype for which is shown in Figure 1. The only assumption I've made is that the application will be developed using a full-fledged object-oriented language such as Java, C++, or Smalltalk. This way, I don't need to worry about modifying the design to meet the architecture for an object-based language such as Visual Basic or for a development environment such as PowerBuilder. The issues I explore in developing an order-entry screen are relevant to developing any object-oriented application.

Figure 1. A screen for creating and displaying an order

The screen in Figure 1 is reached from a higher-level edit screen for customers. Assume the customer information displayed at the top has been input elsewhere. To create order items, users can either input the item number quickly, scan the item via a data input wand, or right-click within the tabular list box to display a pick list dialog from which they can search for and select items. Once the item has been selected, the description and price are displayed by the system. The quantity can be indicated either by scanning items with the data wand or by inputting the number directly into the screen. Finally, the system calculates and displays the order date, order number, item total, overall discount, and grand total. The current business rule is that all orders for more than $1,000 get a 2% discount.

So how do you build this screen? You could build an OrderEntryScreen class that maintained a collection of data representing the order items; after all, you only need to know the item number and the quantity ordered. You can read the pick list of items from the database, so you can change your product line without having to recompile the screen—this table maintains the item number, description, and item price. Because the discounting and totaling logic is straightforward, you can build this logic into the screen. This approach is not very elegant or object-oriented, but it works.

A second approach is to separate the business behavior from the user interface. In other words, it would follow the design pattern promoted by a class-type architecture. The basic idea is that object-oriented software can be separated into four different types of classes: user interface classes that implement the screens and reports for your software, business classes that implement the business and domain logic, persistence classes that encapsulate access to your database, and system classes that wrap communication and operating system services. In this article, I will concentrate on the design of user interface and business classes.

With the screen presented in Figure 1, you need a Customer class that knows its name and address; an Order class that knows how to discount and total itself; an OrderItem class that knows the quantity ordered and can calculate its amount; and an ItemDescription class that knows the item number, description, and price of a single item. Figure 2 depicts the classes, using the Unified Modeling Language (UML) needed to support this design.

Figure 2. An object-oriented design for the order entry screen

I made some interesting design decisions. First, I applied Peter Coad's Item/Item Description pattern, described in "Object-Oriented Patterns" (Communications of the ACM, 1992), for the OrderItem and ItemDescription classes. This pattern advises you to separate descriptive information applicable to many instances into a class of its own. For example, without the ItemDescription class, every OrderItem instance would need to maintain its description even when several orders for the same type of item exist. Second, accessor methods, also known as getters and setters, are used throughout the design to encapsulate the implementation of the classes. This lets you change your implementation without affecting other classes that collaborate with the class you are changing. Third, the OrderEntryScreen class depends on three of the four business classes—it is unaware of the ItemDes cription class.

Figure 2 uses a common approach to design using accessors—all attributes are given private visibility and getters and setters are selectively defined to be public, protected, or private. A quick review of visibility: methods or attributes that are public are accessible by all classes within your application; those that are protected are visible only to the class and subclasses in which they are defined; those that are private are accessible only within the class in which they are defined. This design approach lets you make it appear that classes have attributes even if they don't. For example, the getter method getTotal() in the Order class makes it appear as if Order objects know their totals. But in this current implementation, the Order object calculates the total on-the-fly. A second example is the OrderItem class, which has a getDescription() method that makes it appear that order items know their description when in fact they obtain this information from their corresponding ItemDescription object.

Which approach is better? The answer depends on your situation. If you are in a business environment where your users' requirements never change, then either approach works well. However, if you are in a changing business environment, the second approach is superior since it separates behavior into user interface and business classes.

For example, consider the impact of potential requirement changes. What would happen if you had to add the ability to produce a printed invoice? What would happen if new discounting strategies were developed, including those based on the type of customer making the order and the kind of order items being purchased? As you can imagine, these discounting strategies could become quite complex and would be limited only by the imagination of your marketing department (danger, Will Robinson, danger!).

Consider the impact requirements changes would have on the "build it all in the screen" approach. To add the ability to print an invoice, you would have to develop a second class that could implement the same sort of behavior as the screen, or, minimally, it would take a complex data structure generated by the screen class that represents the order. The addition of new forms of discounting would prove daunting for this approach, requiring complex programming in your screen that would quickly reveal its brittle nature.

Now consider the impact to the class-type architecture approach, the design for which is presented in Figure 3. The first thing you'll notice is that nothing changes in the screen class—the interfaces to the Customer, Order, and OrderItem classes have remained the same (remember what I said about accessor methods?). So, if you have taken a thin-client or n-tier client/server approach to development, you can add the new discounting strategies without having to redeploy your user interface.

Figure 3. Design for the improved order screen

Second, it's easy to add the Invoice class, as it merely needs to collaborate with the existing business classes. Third, the Discounter and DiscountStrategy classes add discounting to the application. The Discounter class calculates the discount for Order and OrderItem objects by applying DiscountStrategy objects to them. DiscountStrategy, likely a class hierarchy or aggregation of classes, implements various approaches to discounting such as flat percentage discounts, tiered discounts, customer-type discounts, and so on. The advantage of this approach is that you can add new discounting strategies easily, an important feature considering the tendencies of your marketing department (my experience is that marketing people are far too creative for their own good). As you can see, the second approach is easier to maintain and extend.

What lessons can you learn from this article? Think before you code. An investment of a couple of hours sketching out a design for the order entry screen presented here resulted in an application that was easy to maintain and enhance. Second, use accessor methods. These helped me change my design strategy easily. Third, develop the discipline to follow the class-type architecture: even a simple thing like totaling order items can be performed by the business classes, rather than the user interface classes. Never forget that business logic, even simple business logic, belongs only in business classes.

Fourth, assume your requirements will change and you'll have to maintain and extend your application over time. Fifth, follow the class-type architecture approach regardless of your hardware architecture. This approach applies to stand-alone applications running on a single machine as well as applications distributed across several machines. The most effective way to develop applications is to understand the problem first, design a solution to it second, and code it third.

Scott Ambler is the author of the Jolt Productivity Award-winning Building Object Applications That Work (SIGS Books, 1997) and The Object Primer (SIGS Books, 1995). You can reach him through Software Development magazine.

© 1998 Miller Freeman Inc.

Comments? Send us e-mail.