|< Free Open Study >|
3.7 The Role of Agent Classes
Another interesting point to consider can be summarized in the following riddle posed at a conference several years ago by Meiler Page-Jones (OOPSLA '87):
While this sounds a bit silly, it brings up an interesting point. One group in a design course that I taught laughed at this riddle, but then spent 30 minutes during a design exercise arguing over the design of a library system. They could not decide if a book should send the bookshelf the book_yourself message or if a bookshelf should send the book the shelf_yourself message. The problem in both these examples is the same. There is a key element missing, namely, the object-oriented farmer and the object-oriented librarian. Are these abstractions classes?
During analysis it is common to model the real world whenever possible. The design process then modifies this real-world model in favor of heuristics like distributing system intelligence and avoiding god classes. The object-oriented farmer and librarian are examples of special classes called agents. Agents are often modeled as classes during analysis in a form such as that shown in Figure 3.17.
At design time we need to ask ourselves, "Of what use is the object-oriented librarian?" It is often the case that agent classes are irrelevant classes. The librarian class simply accepts messages from book and bookshelf and resends them to the desired target. Why not eliminate the librarian and reduce the number of classes and collaborations in our design (see Figure 3.18)?
In many cases this is exactly what we want to do. But what if the librarian has other useful behavior like checking the due data of books, sending out library fine notices, ordering new books? We could add this additional functionality to the Book and BookShelf; however, it often occurs that these two classes become increasingly complex. Based on the need for distribution of system intelligence, we use the agent class to offload some of the work. There is nothing wrong with leaving agent classes in a design if they capture a useful abstraction. Keeping irrelevant agents in a system overly complicates the design, with no benefit to the designer.
During a critique of the design in Figure 3.18, it is common for two designers to get into a long discussion as to whether the Book or the BookShelf should initiate the message. These arguments are often unsolvable since the logical design of the system often sees zero trade-off between the two choices. Physical design (i.e., considerations of efficiency with regard to software and hardware platforms) often shows one solution to be more expensive than the other. If that is not the case, then designers can simply flip a coin to settle the discussion.
Another common example of useless agents invading a system can be seen in the domain of an automatic teller machine. Many designers first view the ATM domain as having three high-level classes: the Bank, the Network, and the ATM itself. The Network is placed in the design since it is a good candidate for a key abstraction of the system. The designer later realizes that the Network does nothing except transfer messages between the ATM and the Bank. For this reason, the Network is often thrown out as a useless agent. The Bank and ATM send messages directly between each other. Much later in low-level design, the system designer realizes that methods sent by the ATM to the Bank need the use of some external network. Not wishing to be dependent on one type of network, the system designer creates a network wrapper class to shield the classes of the domain model (i.e., the key abstractions) from the physical network being used by the system. This network wrapper class is considered an implementation class. It is not needed to model the system. It was created solely for physical design reasons, flexibility in this case. Object-oriented designers often state that implementation-level classes should be kept completely separate from domain model classes to avoid confusion.
This heuristic is in violation of Jacobson's methodology, which argues that the library agent class is decoupling books from bookshelves and should therefore be kept in the system. It is fair to state that we have made the bookshelf class less reusable, and more bound to one domain, because the policy of placing books on bookshelves in a library has been encoded into the bookshelf class. If I want to reuse the bookshelf in my living room, I will have a problem because I do not want my books sorted via the Dewey decimal system. I want to sort my books as computer books on the first shelf, science fiction on the second, cookbooks and gardening books on the third shelf, and everything else on the fourth shelf. However, what will a bookshelf do if I place the policy of placing books on the shelf in a librarian? It simply has gets and sets, it is reusable because it is a mindless class, no more interesting than a linked list. The librarian has only behavior, no data. The bookshelf has only data, no meaningful behavior. We have separated data and behavior under the guise of software reuse. While the thought of books putting themselves on shelves seems very disturbing, the disturbance is due to the real-world nature of the domain. When we examine the design of the automatic teller machine in Chapter 11, we will see agent classes no less interesting than the librarian tossed out of the system with no such disturbance. This will be due to the domain being more abstract.
|< Free Open Study >|