< Day Day Up > |
Many objects have states. The behavior of such an object differs depending on its current condition: the state that it is in. Thinking in terms of states of objects, and what an object can do in each state, can simplify your code. For example, the state of a file object can be NotOpen , OpenForReading , OpenForWriting , or OpenForReadingAndWriting . A file object in the NotOpen state cannot be read or written. Events, such as the calling of an object's method, can alter the state of the object. Calling the open method for a file object can transform the state into OpenForReading , OpenForWriting , or OpenForReadingAndWriting , or it might leave the state as NotOpen , if the file is unavailable. 9.3.1. State DiagramsIn Sam's system, a CDDisc has the state Rented or NotRented . A CDDisc that is Rented cannot be rented again. You can depict the transition between these states by using a state diagram, such as that shown in Figure 9-2. Figure 9-2. CDDisc state diagramState diagrams are not just for developers. They also help users specify system behavior. They help explain how the system's state changes in response to operations, and they can clarify missing specifications. Suppose that Sam wanted to track lost CDDisc s. We prepare a state diagram (shown in Figure 9-3) to demonstrate the transitions between the Lost and InService states and the events that cause these transitions. Figure 9-3. CDDisc service state diagramThis second state diagram for CDDisc s brings up a number of issues. Is the Service state independent of the Rental state? Can a Rented CDDisc become Lost only when it is Rented ? Can you rent a Lost CDDisc ? Thinking in terms of states can help clarify both the user and developer's understanding of the system. 9.3.2. Representing Binary StatesYou can represent an object's state in several ways. For a condition that has only two values, such as Rented/NotRented , the state can be kept as a binary value. If external methods require the value of the state, it is returned by a method to hide its actual implementation. For example, in the version of Sam's system prior to this chapter, the state was represented by whether the_rental attribute of CDDisc referred to null or to a Rental . The is_rented( ) method in CDDisc returns the result of this comparison. With the Rental association introduced in this chapter, the state of a CDDisc is now represented by whether a current Rental for the CDDisc exists in the RentalCollection . The retrieve_current_rental_for_cd_disc( ) in RentalCollection indicates the state by returning either the Rental or null . 9.3.3. More Than Two StatesFor conditions that can take on a larger number of states, an explicit state mechanism is recommended. The mechanism can be separate classes, an attribute, or the State pattern (see Design Patterns by Erich Gamma et al.). For example, as noted in Chapter 7, the state of a Customer could be Regular , Inactive , and NeverAgain . The third value refers to customers who should never be allowed to rent due to their history of not returning rentals. You could use three classes, such as RegularCustomer , InactiveCustomer , and NeverAgainCustomer , all derived from Customer . However, it is usually difficult to alter the class of an object when its state changes. For classes for which the value of the state alters only a single behavior, an enumeration might be appropriate. For example, the state could be kept in an attribute of the type CustomerState : enumeration CustomerState {Regular, Inactive, NeverAgain} If there are more behavior differences between the states, the State pattern is desirable. With the State pattern, the behavior is delegated to objects that each represent a different state. The user sees objects of a single class (e.g., Customer ), and not the state objects (e.g., RegularState , InactiveState , and NeverAgainState ), as shown in Figure 9-4. It is easy to convert Customer s from one state to another with the State pattern by changing the state object to which the behavior is delegated. Figure 9-4. Customer with states
9.3.4. Check All the Bases to See if Anyone Is OnAre there other states for a Rental ? The late/overdue misunderstanding we discovered in the last chapter applies to the Current / Completed state. By the definitions of Late and Overdue , a Rental that is Current can be Overdue or NotOverdue . This condition is dynamic: it changes as time goes on. A Rental that is Completed can be Late or NotLate . This condition is static: once a Rental ends, it is forever going to be Late or NotLate . A Completed Rental cannot be Overdue , nor can a Current Rental be Late . These states with their substates seem to cover all the bases for a Rental at this point. Depending on Sam's future desires for record keeping, we might create states for Rental s for other conditions, such as EndedByLossOfCDDisc .
|
< Day Day Up > |