Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java How to Program, Fourth Edition - Deitel H., Deitel P.pdf
Скачиваний:
58
Добавлен:
24.05.2014
Размер:
14.17 Mб
Скачать

Chapter 15

Multithreading

877

The constructor

public Thread( ThreadGroup threadGroup, Runnable runnableObject )

constructs a Thread that belongs to threadGroup and that invokes the run method of runnableObject when the thread is assigned a processor to begin execution.

The constructor

public Thread( ThreadGroup threadGroup, Runnable runnableObject, String stringName )

constructs a Thread that belongs to threadGroup and that invokes the run method of runnableObject when the thread is assigned a processor to begin execution. The name of this Thread is indicated by stringName.

Class ThreadGroup contains many methods for processing groups of threads. Some of these methods are summarized here. For more information on these methods, see the Java API documentation.

1.Method activeCount reports the number of active threads in a thread group plus the number of active threads in all its child thread groups.

2.Method enumerate has four versions. Two versions copy into an array of Thread references the active threads in the ThreadGroup (one of these also allows you to recursively get copies of all the active threads in child ThreadGroup). Two versions copy into an array of ThreadGroup references the active child thread groups in the ThreadGroup (one of these also allows you to recursively get copies of all the active thread groups in all the child ThreadGroups).

3.Method getMaxPriority returns the maximum priority of a ThreadGroup. Method setMaxPriority sets a new maximum priority for a ThreadGroup.

4.Method getName returns as a String the ThreadGroup’s name.

5.Method getParent determines the parent of a thread group.

6.Method parentOf returns true if the ThreadGroup to which the message is sent is the parent of, or the same as, the ThreadGroup supplied as an argument and returns false otherwise.

Testing and Debugging Tip 15.5

Method list lists the ThreadGroup. This can help in debugging.

15.12 (Optional Case Study) Thinking About Objects:

Multithreading

Real-world objects perform their operations independently of one another and concurrently (in parallel). As you learned in this chapter, Java is a multithreaded programming language that facilitates the implementation of concurrent activities. The UML also contains support for designing concurrent models, as we will see shortly. In this section, we discuss how our simulation benefits from multithreading.

878

Multithreading

Chapter 15

In “Thinking About Objects” Section 10.22, we encountered a problem with the collaboration diagram of Fig. 10.26—the waitingPassenger (the Person waiting to ride the Elevator) always enters the Elevator before the ridingPassenger (the Person riding the Elevator) exits. Proper use of multithreading in Java avoids this problem by guaranteeing that the waitingPassenger must wait for the ridingPassenger to exit the Elevator—as would happen in real life. In our collaboration diagrams, objects pass messages to other objects by calling methods of those other objects— a sending object may proceed only after a method returns. Java refers to such a message pass as a synchronous call. However, the synchronous call is not synchronized, because several objects may access the method at the same time—the synchronous call cannot guarantee exclusivity to one object. This poses a problem when we model our elevator simulation, because according to Fig. 10.26, the waitingPassenger and the ridingPassenger may occupy the Elevator at the same time, which violates the “capacity-of-one” requirement specified in the problem statement. In this section, we use a synchronized method to guarantee that only one Person may occupy the Elevator at a time.

Threads, Active Classes and Synchronized Methods

Java uses threads—flows of program control independent of other flows—to represent independent, concurrent activities. The UML provides the notion of an active class to represent a thread. Classes Elevator and Person are active classes (threads), because their objects must be able to operate concurrently and independently of one another and of other objects in the system. For example, the Elevator must be able to move between Floors while a Person is walking on a Floor. Figure 15.8 updates the collaboration diagram of Fig. 10.26 to support active classes, which are denoted by a thick black border in the diagram. To ensure that Persons enter and exit the Elevator in the proper order, we require a specific order in which to send messages—the Elevator must send message

3.3.1 (ridingPassenger exits) before sending message 3.2.1.1 (waitingPassenger enters the Elevator). The UML provides a notation to allow synchronization in collaboration diagrams—if we have two messages A and B, the notation B/A indicates that message A must wait for B to complete before message A occurs. For example, the 3.3.1/3.2.1.1 notation before the enterElevator message indicates that waitingPassenger must wait for ridingPassenger to exit the Elevator (message 3.3.1) before entering (message 3.2.1.1).

Software Engineering Observation 15.5

Messages in collaboration diagrams must complete in order (e.g., message 3.1 must com- plete before issuing message 3.2). However, messages between active classes may specify different ordering as necessary to guarantee synchronization between certain messages.

A Person must synchronize with the Elevator when traveling to guarantee that only one Person occupies the Elevator at a time. In Fig. 15.8, we include the ride message (3.2.1.2) to represent the Person riding the Elevator to the other Floor. The {concurrent} keyword placed after the ride message indicates that method ride is synchronized when we implement our design in Java. The Elevator contains method ride for the Person to allow the synchronization.

Chapter 15

 

Multithreading

879

 

<<parameter>>

 

 

 

(DoorEvent)

 

 

3.2.1 : doorOpened( )

 

3.2 : openDoor( )

 

 

firstFloorDoor : Door

 

4.1.1 : resetButton( )

 

4.2.1 : turnOnLight( )

 

firstFloorButton : Button

: ElevatorShaft

firstFloorLight : Light

 

4.1 : elevatorArrived( )

4.2 : elevatorArrived( )

 

 

4 : elevatorArrived( )

 

waitingPassenger : Person

ridingPassenger : Person

3.3.1 / 3.2.1.1 : enterElevator( )

 

 

: Elevator

 

3.2.1.2 : ride( )

 

3.3.1 : exitElevator( )

{concurrent}

 

3.3 : doorOpened( )

1 : elevatorArrived( )

 

3 : elevator

 

 

2 : elevator

Arrived( )

 

Arrived( )

 

 

elevatorButton : Button

elevatorDoor : Door

 

: Bell

1.1 : resetButton( )

3.1 : openDoor( )

 

2.1 : ringBell( )

<<parameter>>

<<parameter>>

(ElevatorMoveEvent)

(Location)

Fig. 15.8 Modified collaboration diagram with active classes for passengers entering and exiting the Elevator.

public synchronized void ride()

{

try {

Thread.sleep( maxTravelTime );

}

catch ( InterruptedException interruptedException ) {

//method doorOpened in Person interrupts method sleep;

//Person has finished riding Elevator

}

}

880

Multithreading

Chapter 15

Method ride guarantees that only one Person may ride the Elevator at a time— as described in Section 15.5, only one synchronized method may be active on an object at once, so all other Person threads attempting to invoke ride must wait for the current thread to exit method ride.

Method ride invokes static method sleep of class Thread to put the Person thread into the sleep state, which represents the Person waiting for the ride to complete. We must specify the maximum amount of time that a Person will wait for the Elevator to complete traveling—however, there is no such information specified in the problem statement. We introduce a new attribute that represents this time—maxTravelTime, to which we arbitrarily assign a value of 10 minutes (i.e., a Person will wait 10 minutes for the travel to complete). Attribute maxTravelTime is a safeguard in case the Elevator— for whatever reason—never reaches the other Floor. The Person should never have to wait this long—if the Person waits 10 minutes, then the Elevator is broken, and we assume that our Person crawls out of the Elevator and exits the simulation.

Software Engineering Observation 15.6

In a software-development process, the analysis phase yields a requirements document (e.g., our problem statement). As we continue the design and implementation phase, we discover additional issues that were not apparent to us at the analysis phase. As designers, we must anticipate these issues and deal with them accordingly.

Software Engineering Observation 15.7

One false assumption to make is that the system requirements remain stable (i.e., they pro- vide all information necessary to build the system) throughout the analysis and design phases. In large systems that have long implementation phases, requirements can, and often do, change to accommodate those issues that were not apparent during analysis.

If our Elevator works correctly, the Elevator travels for five seconds—specifi- cally, invoking method sleep halts the Elevator’s thread for five seconds to simulate the travel. When the Elevator thread awakens, it sends elevatorArrived events as described in Section 10.22. The elevatorDoor receives this event and invokes method doorOpened (message 3.3) of the ridingPassenger, as in:

public void doorOpened( DoorEvent doorEvent )

{

//set Person on Floor where Door opened setLocation( doorEvent.getLocation() );

//interrupt Person's sleep method in run method and

//Elevator's ride method

interrupt();

}

Method doorOpened sets the ridingPassenger’s Location to the Floor at which the Elevator arrived, then calls the ridingPassenger thread’s interrupt method. The interrupt method terminates the sleep method invoked in method ride, method ride terminates, and the ridingPassenger leaves the Elevator, then exits the simulation. When the ridingPassenger exits the Elevator, the ridingPassenger releases the monitor on the Elevator object, which allows the waitingPassenger to invoke the ride method and obtain the monitor. Now, the waitingPassenger may invoke method ride to ride the Elevator.

Chapter 15

Multithreading

881

The ridingPassenger does not need to send the exitElevator message (message 3.3.1) to the Elevator, because the waitingPassenger cannot invoke ride until the ridingPassenger releases the Elevator’s monitor—the ridingPassenger releases the monitor when the ridingPassenger thread exits method ride after calling its interrupt method. Therefore, the Person thread’s interrupt method is equivalent to the exitElevator method (except that the Person sends itself the interrupt message), and we can substitute method interrupt for method exitElevator. Also, we can combine methods ride and enterElevator to handle both entering and riding the Elevator—our system needs only method ride, which allows a Person to obtain a monitor on the Elevator. As we implement our model in Appendix H, we use our collaboration diagram to help generate code in Java—however, we will make subtle “Java-specific” adjustments to our code to guarantee that the Persons enter and exit the Elevator correctly.

Sequence Diagrams

We now present the other type of interaction diagram, called a sequence diagram. Like the collaboration diagram, the sequence diagram shows interactions among objects; however, the sequence diagram emphasizes how messages are sent between objects over time. Both diagrams model interactions in a system. Collaboration diagrams emphasize what objects interact in a system, and sequence diagrams emphasize when these interactions occur.

Figure 15.9 is the sequence diagram for a Person changing floors. A rectangle enclosing the name of an object represents that object. We write object names in sequence diagrams using the same convention we have been using with collaboration diagrams. The dotted line extending down from an object’s rectangle is that object’s lifeline, which represents the progression of time. Actions occur along an object’s lifeline in chronological order from top to bottom—an action near the top of a lifeline happens before an action near the bottom. We provide several notes in this diagram to clarify where the Person exists in the simulation. Note that the diagram includes several dashed arrows. These arrows represent “return messages,” or the return of control to the sending object. Every message ultimately yields a return message. Showing return messages is not mandatory in a sequence diagram—we show return messages for clarity.

Message passing in sequence diagrams is similar to that in collaboration diagrams. An arrow extending from the object sending the message to the object receiving the message represents a message between two objects. The arrowhead points to the rectangle on the receiving object’s lifeline. As previously mentioned, when an object returns control, a return message—represented as a dashed line with an arrowhead—extends from the object returning control to the object that initially sent the message.

The sequence in Fig. 15.9 begins when a Person presses a Button on a Floor by sending message pressButton to that Button. The Button then requests the Elevator by sending message requestElevator to the Elevator.

The Person must wait for the Elevator to process this message before continuing. However, the Person does not need to wait for the Elevator’s arrival before proceeding with other actions. In our simulation, we force the Person to wait, but we could have had the Person perform other actions, such as read a newspaper, sway back and forth or place a call on a cell phone as the Elevator travels to the Floor of the Person.

882

Multithreading

Chapter 15

floorButton : Button

 

elevator: Elevator

 

elevatorDoor : Door

 

 

 

 

 

 

 

 

 

 

person : Person

pressButton( )

person waits for elevator

person enters elevator

 

 

elevatorButton : Button

 

 

 

 

floorDoor : Door

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[Elevatoron

 

 

 

 

 

 

 

opposite

 

 

 

requestElevator( )

 

Floor of

 

 

 

 

 

 

[Elevator

 

request]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

on same

 

 

 

 

 

elevator travels

 

 

 

 

Floor of

 

 

 

 

 

 

to other floor

 

 

 

 

request]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

elevatorArrived( )

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

doorOpened( )

 

 

 

 

 

 

 

 

 

openDoor( )

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

pressButton( ) buttonPressed( )

setMoving( true )

closeDoor( )

closeDoor( )

ride( ) {concurrent}

 

elevator travels

setMoving( false )

person rides

5 seconds

elevatorArrived( )

elevator

 

 

openDoor( )

 

 

 

doorOpened( )

 

interrupt( )

terminate

 

method ride

 

 

 

person exits

 

 

elevator

 

 

Fig. 15.9 Sequence diagram for a single Person changing floors in system.

Note the split in flow for the Elevator after being requested; the flow of execution depends on which Floor generated the request. If the Elevator is on a different Floor

Chapter 15

Multithreading

883

than the request, the Elevator must move to the Floor on which the Person is waiting. To save space, the note informing that the Elevator moves to the other Floor represents this sequence (We will construct this sequence momentarily when we discuss how the Person rides the Elevator to the other Floor.) When the Elevator travels to the other Floor, the branched sequence merges with the original sequence in the Elevator’s lifeline, and the elevatorDoor sends an elevatorArrived message to the elevatorDoor upon arrival.

If the Elevator is on the same Floor as the request, the elevatorDoor immediately sends an elevatorArrived message to the elevatorDoor upon arrival. The elevatorDoor receives the arrival message and opens the Door on the arrival Floor. This door sends a doorOpened message to the Person—that Person then enters the

Elevator.

The Person then presses the elevatorButton, which sends a buttonPressed event to the Elevator. The Elevator gets ready to leave by calling its private method setMoving, which changes the Elevator’s boolean attribute moving to true. The Elevator then closes the elevatorDoor, which closes the Door on that Floor. The Person then rides the Elevator by invoking the Elevator’s synchronized method ride. As in the collaboration diagram, the {concurrent} keyword placed after method ride indicates the method is synchronized, when implemented in Java.

The remainder of the diagram shows the sequence after the Elevator’s arrival at the destination Floor (also described in Fig. 15.9). Upon arrival, the Elevator stops moving by calling private method setMoving, which sets attribute moving to false. The Elevator then sends an elevatorArrived message to the ElevatorDoor, which opens the Door on that Floor and sends the Person a doorOpened message. Method doorOpened wakes the sleeping Person’s thread by invoking method interrupt, causing method ride to terminate and return the Person’s thread to the “ready” state. The Person exits the simulation shortly afterwards. Note the large “X” at the bottom of the Person’s lifeline. In a sequence diagram, this “X” indicates that the associated object destroys itself (in Java, the Person object is marked for garbage collection).

Our Final Class Diagram

The integration of multithreading in our elevator model concludes the design of the model. We implement this model in Appendix H. Figure 15.10 presents the complete class diagram we use when implementing the model. Note that the major difference between the class diagrams of Fig. 15.10 and Fig. 10.31 is the presence of active classes in Fig. 15.10. We have established that classes Elevator and Person are active classes. However, the problem statement mentioned that “if a person neither enters nor requests the elevator, the elevator closes its door.” Having discussed multithreading, we believe that a better requirement would be for the Doors to close automatically (using a thread) if they have been open for more than a brief period (e.g., three seconds). In addition, although not mentioned in the problem statement, the Lights should turn off automatical- ly—currently, the Lights turn off only when the Elevator departs from a Floor. We mark the Doors and Lights as active classes to handle this change. We implement this change in Appendix H.

884

Multithreading

Chapter 15

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Creates

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

1

 

 

2

 

 

 

 

 

 

 

 

 

 

 

Light

 

 

Turns

 

 

 

 

 

ElevatorModel

 

 

 

 

Floor

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1 on/off

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Signals

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

arrival

 

 

 

 

 

 

1

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ElevatorShaft

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Signals

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

arrival

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Opens /

 

 

 

 

 

 

 

Resets

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Closes

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0..*

 

 

2

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

2

 

 

 

Presses

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Person

 

 

 

Door

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Button

 

 

 

 

 

 

 

 

 

 

 

Signals

 

 

 

 

 

 

 

 

 

1

1

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

arrival

 

 

 

 

 

 

 

 

 

 

 

 

 

1

1

 

 

 

 

 

1

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Informs of

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

opening

 

 

 

 

 

 

 

 

 

 

 

Signals

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

Signals to

 

 

 

 

 

 

 

 

 

 

 

 

arrival

 

 

 

 

 

1

 

 

Elevator

 

 

 

move

 

 

 

 

Occupies

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

Signals

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

1

 

 

 

arrival

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Signals

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

arrival

 

 

 

 

 

 

 

 

 

2

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

Rings

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Location

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Bell

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Fig. 15.10 Final class diagram of the elevator simulation

Figure 15.11 presents the attributes and operations for all classes in Fig. 15.10. We use both diagrams to implement the model. We have omitted method enterElevator and exitElevator from class Elevator, because as discussed in the interaction diagrams, method ride appears to handle the Person’s entering, riding and exiting the Elevator. In addition, we have replaced method departElevator with private method setMoving, because according to Fig. 15.9, method setMoving provides the service that allows the Elevator to depart from a Floor. We also include private attribute maxTravelTime, which represents the maximum time the Person will wait

Chapter 15

Multithreading

885

to ride the Elevator, to class Person. We assign maxTravelTime a value of 10 minutes (10 * 60 seconds). We will use these class diagrams to implement our Java code in Appendix H, but we will continue making subtle “Java-specific” adjustments to code. In the appendices, for each class, we create methods that access object references and implement interface methods.

In “Thinking About Objects” Section 22.9, we design the view—the display of our model. When we implement this display in Appendix I, we will have a fully functional 3,594-line elevator simulation.

ElevatorModel

- numberOfPeople : Integer = 0

+ addPerson( ) : void

Location

- locationName : String

# setLocationName( String ) : void

+getLocationName( ) : String

+getButton( ) : Button

+getDoor( ) : Door

Person

-ID : Integer

-moving : Boolean = true

-location : Location

-maxTravelTime : Integer = 10 * 60

+ doorOpened( ) : void

Elevator

-moving : Boolean = false

-summoned : Boolean = false

-currentFloor : Location

-destinationFloor : Location

-travelTime : Integer = 5

+ride( ) : void

+requestElevator( ) : void

– setMoving( Boolean ) : void

+getButton( ) : Button

+getDoor( ) : Door

Light

- lightOn : Boolean = false

+turnOnLight( ) : void

+turnOffLight( ) : void

ElevatorShaft

Floor

+getButton( ) : Button

+getDoor( ) : Door

Bell

+ ringBell( ) : void

Button

-pressed : Boolean = false

+resetButton( ) : void

+pressButton( ) : void

Door

-open : Boolean = false

+openDoor( ) : void

+closeDoor( ) : void

Fig. 15.11 Final class diagram with attributes and operations.