9.3. The State of an Object

 <  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 Diagrams

In 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 diagram

State 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 diagram

This 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 States

You 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 States

For 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

PRINTING THE UNPRINTABLE

I once worked with a company that programmed the reservation system for a large airline. When they first developed electronic ticketing, it was treated as a form of regular ticketing. The system had states for a reservation: reserved, ticketed, and so forth. It was pretty clear what ticketed meant : the ticket had been printed. A confirmation had come back from the ticketing agency that the printer had successfully printed the ticket. A number of decisions were based on ticketing, such as whether a person would be charged if he made a change to his ticket.

The question arose as to when an electronic ticket was considered ticketed. Since an electronic ticket was never printed, it was never considered ticketed. A passenger could make a change up until he boarded the plane and not be charged a change fee. (This condition has since been corrected.)

When using states, be sure that each state reflects the desired behavior. Don't force fit new states into existing ones.


SEE WHAT CONDITION YOUR CONDITION IS IN

Use state-based analysis to examine object behavior . [*]


[*] A reviewer noted that Boris Beizer was an early proponent of state-based analysis and testing. See Software System Testing and Quality Assurance by Boris Beizer (Van Nostrand Reinhold/Wiley, 1984).

9.3.4. Check All the Bases to See if Anyone Is On

Are 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 .

THE BIG STATE SWITCH

I heard a story about one of the original designers of an AT&T telephone switch. He spent several months investigating all the possible states of a telephone call and what caused a transition from one state to another. The managers were getting concerned . All he did was walk around, talk to people, and scribble things on a pad of paper. They did not see any visible progress. One day, he announced that he was done. He turned the state diagram over to a coder. The coder completed the job in a few weeks. That program formed the basis for the AT&T switch for many years .

This is an example of how state-based design can result in a very maintainable system.


 <  Day Day Up  >  


Prefactoring
Prefactoring: Extreme Abstraction, Extreme Separation, Extreme Readability
ISBN: 0596008740
EAN: 2147483647
Year: 2005
Pages: 175
Authors: Ken Pugh

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net