|
|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SOA World Conference
Virtualization Conference $200 Savings Expire May 16, 2008... – Register Today!
SYS-CON.TV |
TOP THREE LINKS YOU MUST CLICK ON Advanced Java
Turning Components into Domain GUI Objects (DGO)
Improving your design
By: Ted Young
Digg This!
When creating user interfaces for a data entry application (as opposed to one where the user is directly manipulating graphics, such as a network diagram designer), a typical scenario is to create some containers, instantiate their layout managers, and add some components such as JLabels, JTextFields, or JButtons. When the application needs to gather the information entered by the user, it accesses the components directly. Figure 1 shows a screen with a table of information (a book inventory) and a search area that allows users to find one of the books by various criteria specified in the fields.
![]() To find a book with a given word in its title or description, the user enters the query criteria and presses the "Search" button. After the query has executed, the matching items in the table are then highlighted. Listing 1 shows a typical example of how the code can be written where BookSearchPanel.java creates the GUI components, then adds an action listener to the button that, when pressed, calls a doSearch() method that uses the current component's values to create a search string. (Listings 1-4 can be downloaded from www.sys-con.com/java/sourcec.cfm.) This article shows the limitations of this coding technique and how to improve it by using Domain GUI Objects. Issues with a Typical Solution boolean isSearchInTitle = m_searchInTitleCheckBox.isSelected(); A problem could arise if the user interface changed - the columns to be searched would be specified by selecting items in a JList or highlighting columns in the JTable. The search code would then have to be modified to use the different components, when all that changed is how the GUI is being presented to the user. The explicit knowledge the search logic needs of the presentation components can be improved upon by decoupling the two. Another reason why Listing 1 is so poor is that it's not the responsibility of the search code to determine what the query options are. That logic should be elsewhere, and only the information on what the options are (not how they're represented) should be required by the search code. By separating the two, it's possible to add features such as allowing the user to save searches to replay later. Also, what about testing the search code (because I know all of you unit test your code, right?). The "quick and dirty," tightly coupled implementation is looking less attractive now. Loosening the Coupling public boolean isSearchInTitle() { The presentation logic is encapsulated in BookSearchDgo, which hides its implementation from the code that performs the actual search. This search code can be put in a separate class (BookSearch.java, see Listing 3) that registers itself with the BookSearchDgo (using an ActionListener passed into the DGO's constructor), and when the "Search" button is clicked it queries the BookSearchDgo through its public interface and proceeds on its merry way. public class BookSearch implements ActionListener { Having the BookSearch class instantiate the BookSearchDgo isn't a great way to decouple logic, but the discussion of what creates what and when will have to wait for a future column. If the way the GUI appears is altered (see Figure 2), such as the Match Case radio buttons becoming a single checkbox, the interface remains the same and the search code is unaltered. This is the advantage of separating the GUI from the search or business logic.
![]() Loosening the Coupling Even More The solution, shown in Listing 4, is to loosen the coupling at the point where the search code assumed that it was waiting for the "Search" JButton to be clicked (and therefore the ActionListener to be called). Instead of waiting for a button click, the search code performs the search when a more "functional" or "semantic" event occurs. For this an UpdateSearchListener interface is created with a single callback updateSearch() callback method. interface UpdateSearchListener { The BookSearchDgo accepts an UpdateSearchListener in its constructor public BookSearchDgo(UpdateSearchListener updateSearchListener) and the BookSearch class implements UpdateSearchListener so it's no longer reliant on an ActionPerformed event: public class BookSearch implements UpdateSearchListener { Now the search code doesn't know, or for that matter care, how or why the updateSearch() method was invoked. It could have been that the "Search" button was clicked, one of the checkboxes checked, or just the passage of a specific interval of time. All that the search logic knows is that it needs to update the query, which it still does by getting the search parameters from the DGO that are conveniently passed directly via the updateSearch() method. Lessons Learned
In future columns, I'll show how to handle continuing changes in the requirements that affect the GUI: the items that match the search query need to be highlighted; only items that match the search query are shown (filtering); how to switch between two search modes - easy and advanced; and the need to support searching over a large number of items without affecting performance (or at least perceived performance). LATEST JAVA STORIES & POSTS
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK BREAKING JAVA NEWS
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||