Chapter 20 - Pattens and UML

advertisement
Chapter 20
Patterns and UML
0. Introduction
The design of object oriented software is difficult. The design of reusable object-oriented
software is much harder. Actions and behavior must be identified. The commonalities
among actors and their behavior must be factored out with the correct granularity to
create classes. Commonalities among the classes are used to create inheritance
hierarchies. Experience suggests that reusable and flexible design comes only by repeated
attempts to solve the problem.
In spite of this difficulty good, flexible designs are created. However, experienced
programmers do not solve every problem from scratch. Rather, they remember good
solutions and reuse them. Such a generalized solution is called a pattern. One reviewer1
of Gamma et. al., Design Patterns describes design patterns as "knowledge management".
Booch (Object Oriented Analysis and Design, Benjamin/Cummings, 1994) makes
"pattern scavenging" a part of his formal search for commonalities.
UML stands for Unified Modeling Language. Grady Booch, James Rumbaugh, and Ivar
Jacobson each had software pattern tools that were evolving towards the same collection
of features and capabilities. The three joined forces and formed UML.
UML expresses models of complex situations. It is programming language independent.
It has mechanisms for extension and specialization. UML supports collaborations,
frameworks and patterns.
UML is not a visual programming language. Rather, UML is a graphical modeling
language which communicates a model of a problem. A programming language
communicates an implementation of an algorithm.
1
In www.drbob.com/reviews/0201633612.htm, Robert E. Swart reviewed Gamma, Helm, Johnson and
Vlissides, Design Patterns, 1995, Addison Wesley.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 2
1. Outline of topics in the chapter
20.1 Patterns
Adapter Pattern
The Model-View-Controller Pattern
Example: A Sorting Pattern
Tip: Pragmatics and Patterns
Pattern Formalism
20.2 UML
History of UML
UML Class Diagrams
Class Interactions
2. General remarks on the chapter
20.1 Patterns
The text says a pattern is a design principle that applies across a variety of software
applications.
Much as a novelist or a playwright reuses plots, a good programmer reuses and abstracts
good solutions. We pointed out above that experienced programmers do not solve every
problem from first principles, rather they make patterns out of good solutions they find
for problems. Thus patterns are generalized solutions to whole classes of problems. The
general principle is "Complex systems have common patterns."
We have examined iterators in connection with STL and other containers but we have not
examined the iterator as a pattern. The text remarks that there would be a large amount of
detail to learn if each iterator type had to be learned without the iterator strength
hierarchy. The iterator pattern is part of the Container pattern. The general pattern is
called the container-iterator or just iterator patterns.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 3
Here I mention some classes of patterns from Gamma, Helm, Johnson and Vlissides,
Design Patterns, 1995, Addison Wesley.
Gamma et. al. classify the pattern they study into

Creational Patterns, including Factory, Builder and Singleton.

Structural Patterns, including Adapter, Composite and Proxy

Behavioral Patterns, including Iterator, Observer, Template and Visitor.
A good patterns web reference is http://www.cs.wustl.edu/~schmidt/patterns.html or
you can use one of the web search engines.
Adapter Pattern
In Design Patterns, page 139, Gamma et. al. says that the intent of the adapter design
pattern is to convert the interface of a class, providing a different interface that clients
expect. The adapter pattern lets classes work together that couldn't otherwise because of
incompatible interfaces.
The STL stack and queue adapt one of the sequence containers to provide a stack
or a queue interface. How to add the interface is an implementation detail which is not
specified by the adapter pattern. This is similar to a class or Abstract Data Type interface
that does not specify implementation details. Patterns are concerned with the interface,
not the implementation.
The Model-View-Controller Pattern
This pattern is a way of dividing the i/o and algorithm into three parts. The model is the
algorithmic part of the pattern. It carries out the work of the pattern. The view gives a
picture of the object's state. It corresponds to the output of a program. The controller is
the input part. It provides commands or supplies data (or both). Though all applications
fit this model, it fits a GUI (Graphical User Interface) particularly well.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 4
Example: A Sorting Pattern (and) Efficiency of the Sorting Pattern
(and Some Comments)
Several papers have been published since 1979 that illustrate patterns in and connections
between various sorting algorithms. The ideas are quite generic, so I will not try to chase
down these papers.
Efficient sorts split the container being sorted into two more or less equal parts, then do
something to the parts, and finally, put the parts back together so that the result is sorted.
I will call these the "split" and the "join". How reliably an algorithm performs with high
efficiency depends on how reliably we can predict whether the pieces will have the same
size. In algorithms courses it is proved that O(log N) is the best possible runtime for
sorts that work by swapping elements. If the pieces are of equal size, a sort pattern will
run in O(N*log N) time where N is the number of elements in the container.
The quick sort does a difficult split into pieces whose relative sizes cannot be guaranteed,
but with high probability are almost equal is size. The join is easy. The run time is
O(N*log N) unless we are so unfortunate as to have splits all have one subarray quite
small and one subarray quite large. Then the algorithm "goes quadratic" that is, the
runtime is O(N2).
The merge sort does an easy split, but a hard join. The two halves are guaranteed to be of
sizes that differ by at most 1, so we are guaranteed O(N*log N) run time.
(Unfortunately, the constant multiplier is larger for the merge sort than the average for
good implementation of the quick sort.)
We could view the selection sort and insertion sort as split/join where the partitions have
sizes 1 and N-1. This analysis suggests that the runtime for these sort algorithms should
be O(N2) (as they are).
Tip: Pragmatics and Patterns (and) Pattern Formalism
You don't need to be rigid in following the details. A pattern is designed to guide you, not
put you in a strait jacket. The text points out that the quick sort in Display 20.5 rigidly
follows the pattern so the example will be clean. In a real use, several liberties would be
taken.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 5
20.2 UML
Systems programmers have used sketch figures and arrows with scribbled notes in natural
language to specify, build and document systems. Clearly these will continue to be used,
but the UML provides a language for communicating information about complete
systems. The UML fundamentally bridges the gap between requirements and
implementation. The article by Sinan Si Alhir, "From the Unified Modeling Language
(UML) to C++" http://www.dex.com/premier/mgznarch/vcdj/1999/jun99/uml1.asp, was quite
informative.
In one short chapter, our text book cannot even scratch the surface of the things the UML
can do to specify, visualize, construct, document, and communicate a broad array of
differing systems, domains, and processes.
History of UML
Grady Booch, James Rumbaugh, Ivar Jacobson (and others) developed formal pattern
languages for software development. Booch, Rumbaugh and Jacobson each had formed
companies that exploited his pattern tools. While each tool set had its own distinctive
capabilities, each recognized that his tools and the tools being developed by the others in
the three were evolving towards similar features and capabilities. Rumbaugh joined
Booch at Rational, Booch's company in 1994. They released a first draft of the UML. In
late 1995, Ivar Jacobson joined forces with Booch and Rumbaugh to work on UML. The
UML Standard is maintained and implementations are certified by the nonprofit
organization, the Object Management Group (OMG).
UML Class Diagrams
The UML class diagram is a solid-outline rectangle with compartments. There is one
required compartment. There must be

A class name compartment that has the name of the class.
There may be

An attribute compartment containing class state.

An operation compartment that contains a class's operations and methods,

Other compartments for other properties.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 6
The class diagram is the core object-oriented design. It expresses the state and behavior
of the system. The class diagram places the symbols +, #, and – in front of attributes,
operations, methods and other properties to denote the access specified in C++ by
private, protected and public.
Class Interactions
To be useful, classes interact through their member functions, through inheritance and
composition. There are many notations for class interactions. Labeled arrows of various
styles pointing from one class to another be used to indicate interactions between classes.
For example, various annotations are used with arrows from one class diagram to another
to indicate that one class inherits from another.
Class diagrams may be collected together to in packages denoting related behavior.
3. Solutions to, and remarks on, selected Programming Projects
1. QuickSort Pattern implementation. Recode quick-sort implementation using the
modified pattern in the programming tip section, Pragmatics and Patterns.
2. Sorting Pattern using classes. Re do the Sorting pattern using classes. Define a
template abstract class Sort that has a constructor that takes an array argument. The
array to be sorted is the argument. The class Sort will have member functions with the
same names and behavior as in Display 10.2, except they will not have an array
argument. They act on the array stored by the constructor. Define a member function
sort again following the model of Display 20.2. The functions split and join will
be pure virtual functions. Define class MergeSort and class QuickSort that inherit
from and realize the Sorting pattern using the merge sort and quick-sort algorithms
respectively. Each will be required by C++ to implement the member functions split
and join.
Test.
/*2.
This is the file Ch20Prog2.cpp
Sorting Pattern using classes. Do again the Sorting
pattern from Display 20.2 using classes.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 7
Define a template abstract class Sort that has a
constructor that takes an array argument. The array
to be sorted is the argument.
*/
//This is the file sortpattern.cpp from Display 20.2
//modified for Ch20 Program 2
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
template <class T>
class Sort
{
public:
Sort(T a[], int size);
virtual int split(int begin, int end) = 0;
//Rearranges elements [begin, end) of array a into two intervals
//[begin, split) and [splitPt, end), such that the sorting pattern
//works. Returns splitPt.
virtual void join(int begin, int splitPt, int end) = 0;
//Combines in the elements in the two intervals [begin, split) and
//[splitPt, end) in such a way that the sorting pattern works.
void sort(int begin, int end);
//Precondition: Interval [begin, end) of a has elements.
//Postcondition: The values in the interval [begin, end) have
//been rearranged so that a[0]<= a[1]<= ...<= a[(begin - end)-1].
void sort(int numberUsed);
//Precondition: numberUsed <= declared size of the array a.
//The array elements a[0] through a[numberUsed - 1] have values.
//Postcondition: The values of a[0] through a[numberUsed - 1] have
//been rearranged so that a[0] <= a[1] <= ... <= a[numberUsed - 1].
protected:
T * a;
int size;
};
template <class T>
void Sort<T>::sort(int begin, int end)
//Precondition: Interval [begin, end) of a has elements.
//Postcondition: The values in the interval [begin, end) have
//been rearranged so that a[0]<=a[1]<=...<=a[(begin - end)- 1].
{
if ((end - begin) > 1)
{
int splitPt = split(begin, end);
sort(begin, splitPt);
sort(splitPt, end);
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 8
join(begin, splitPt, end);
} //else sorting one (or fewer) elements so do nothing.
}
template <class T>
Sort<T>::Sort(T array[], int arraySize) : a(array), size(arraySize)
{
}
template <class T>
void Sort<T>::sort(int numberUsed)
//Precondition: numberUsed <= declared size of the array a.
//The array elements a[0] through a[numberUsed - 1] have values.
//Postcondition: The values of a[0] through a[numberUsed - 1] have
//been rearranged so that a[0] <= a[1] <= ... <= a[numberUsed - 1].
{
sort(0, numberUsed);
}
template<class T>
class MergeSort : public Sort<T>
{
public:
MergeSort(T a[], int size);
int split(int begin, int end);
//Rearranges elements [begin, end) of array a into two intervals
//[begin, split) and [splitPt, end), such that the sorting pattern
//works.Returns splitPt.
void join(int begin, int splitPt, int end);
//Combines in the elements in the two intervals [begin, split) and
//[splitPt, end)in such a way that the sorting pattern works.
};
template<class T>
MergeSort<T>::MergeSort(T a[], int size) : Sort<T>(a, size){};
//mergesort.cpp: the merge sort implementation of the sorting pattern.
template <class T>
int MergeSort<T>::split(int begin, int end)
{
return ((begin + end)/2);
}
template <class T>
void MergeSort<T>::join(int begin, int splitPt, int end)
{
T *temp;
int intervalSize = (end - begin);
temp = new T[intervalSize];
int nextLeft = begin; //index for first chunk
int nextRight = splitPt; //index for second chunk
int i = 0; //index for temp
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 9
//Merge till one side is exhausted:
while ((nextLeft < splitPt) && (nextRight < end))
{
if (a[nextLeft] < a[nextRight])
{
temp[i] = a[nextLeft];
i++; nextLeft++;
}
else
{
temp[i] = a[nextRight];
i++; nextRight++;
}
}
while (nextLeft < splitPt)//Copy rest of left chunk, if any.
{
temp[i] = a[nextLeft];
i++; nextLeft++;
}
while (nextRight < end) //Copy rest of right chunk, if any.
{
temp[i] = a[nextRight];
i++; nextRight++;
}
for (i = 0; i < intervalSize; i++)
a[begin + i] = temp[i];
}
template<class T>
class QuickSort : public Sort<T>
{
public:
QuickSort(T a[], int size);
int split(int begin, int end);
//Rearranges elements [begin, end) of array a into two intervals
//[begin, split) and [splitPt, end), such that the sorting pattern
//works. Returns splitPt.
void join(int begin, int splitPt, int end);
//Combines in the elements in the two intervals [begin, split)
//and [splitPt, end)in such a way that the sorting pattern works.
};
template<class T>
QuickSort<T>::QuickSort(T a[], int size) : Sort<T>(a, size){};
template<class T>
int QuickSort<T>::split(int begin, int end)
{
T *temp;
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 10
int size = (end - begin);
temp = new T[size];
T splitV = a[begin];
int up = 0;
int down = size - 1;
//Note that a[begin] = splitV is skipped.
for (int i = begin + 1; i < end; i++)
{
if (a[i] <= splitV)
{
temp[up] = a[i];
up++;
}
else
{
temp[down] = a[i];
down--;
}
}
//0 <= up = down < size
temp[up] = a[begin]; //Positions the split value, spliV.
//temp[i] <= splitV for i < up; temp[up] = splitV; temp[i] > splitV
//for i > up.
//So, temp[i] <= temp[j] for i in [0, up) and j in [up, end).
for (i = 0; i < size; i++)
a[begin + i] = temp[i];
if (up > 0)
return (begin + up);
else
return (begin + 1); //Ensures that both pieces are nonempty.
}
template<class T>
void QuickSort<T>::join(int begin, int splitPt, int end)
{
//Nothing to do
}
void fillArray(int a[], int
//Precondition: size is the
//Postcondition: numberUsed
//a[0] through a[numberUsed
//nonnegative integers read
size, int& numberUsed);
declared size of the array a.
is the number of values stored in a.
- 1] have been filled with
from the keyboard.
int main( )
{
cout << "This program sorts numbers from lowest to highest.\n";
int array[10], array2[10], numberUsed;
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 11
fillArray(array, 10, numberUsed);
for(int i = 0; i < 10; i++)
array2[i] = array[i];
QuickSort<int> a(array, 10);
a.sort(numberUsed);
cout << "\n\nIn original order the numbers are:\n";
{
//
//
//
//
VC++ puts the loop control variable OUTSIDE a "for" loop,
whereas the ANSI Standard requires loop control variable INSIDE
a "for" loop. I have put each for loop inside its own block.
with its own loop control.
for (int index = 0; index < numberUsed; index++)
cout << array2[index] << " ";
}
cout << "\nSorted by quick sort, the numbers are:\n";
{
for (int index = 0; index < numberUsed; index++)
cout << array[index] << " ";
}
cout << endl;
MergeSort<int> m(array2, 10);
cout << "\n\nIn original order, the numbers are:\n";
{
for (int index = 0; index < numberUsed; index++)
cout << array2[index] << " ";
}
m.sort(numberUsed);
cout << "\nSorted by merge sort, the numbers are:\n";
{
for (int index = 0; index < numberUsed; index++)
cout << array2[index] << " ";
}
cout << endl;
return 0;
}
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 12
void fillArray(int a[], int size, int& numberUsed)
{
cout << "Enter up to " << size << " nonnegative whole numbers.\n"
<< "Mark the end of the list with a negative number.\n";
int next, index = 0;
cin >> next;
while ((next >= 0) && (index < size))
{
a[index] = next;
index++;
cin >> next;
}
numberUsed = index;
}
3. Vending Machine
4. Elevator – Simple Version
You are given a two-story building that has one elevator. Write a simulation for the
elevator so that building designers can study the elevator system.
Required features:
At the elevator door on each of the two floors there is a call button. Inside the car, there
are door-open door-close and alarm buttons.
Programmer decided details:
Include but do not limit consideration to displays are to be placed at the doors, in the car,
ringing a bell on arrival at a floor, opening and closing of the doors. The programmer
must also decide what outputs are necessary to understanding the simulation.
Sequence of Tasks
Identify the objects and behavior of the objects in the simulation.
Identify the interactions between the objects.
Observe commonalities in behavior to identify the classes.
Identify state that the classes must maintain to be able to control the elevator.
Design and code a simulation of the building's elevator.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 13
Remarks: Clearly passenger load is a concern of building designers. This problem does
not mention random scheduling of times and numbers of passengers to arrive at each of
the two floors. A full simulation for building designers will require this as part of a
simulation of elevator behavior.
This omission is not inadvertent. It is intended that the student design and code the
simulation of the elevator alone, using object oriented design, and using the UML class
description, but not including simulation of passenger load. Such a problem is
significantly more difficult problem.
Narrative of actions to be simulated
I used a narrative an elevator trip from one floor to another to obtain the objects of the
simulation and to suggest some of the interactions.
The following cycle is triggered by the arrival of a passenger.
A passenger building arrives at the elevator door on one of the floors. She presses floor's
call button. If the car is on this floor the door opens immediately. Otherwise the car is
called. The door opens on arrival at floor this floor. The timer on the door closer starts.
Passenger enters and presses the "other floor" button. Either the timer runs its time out or
the button press expires the timer. The door closes in response to timer expiration. Car
direction is set towards the other floor. The car moves to the other floor. Car direction is
toggled. On arrival, the bell rings and the door opens. Passenger leaves.
A slightly simpler scenario that ignores the door timer and simplifies the door behavior
produces an easier solution.
A passenger arrives at the elevator door on one of the two floors. If the elevator car is on
this floor the door is open, otherwise the car is on the other floor and the door is closed.
In this case, she presses the floor's recall button causing the elevator car to move to this
floor. The door opens automatically on arrival at floor this floor. She enters and presses
the "other floor" button in the elevator car. The door closes in response. The car moves to
the other floor. The Floor's "Car Called" display illuminates. On arrival, the elevator
car's bell rings, and the door opens. Passenger leaves. The door remains open on this
floor until another passenger arrives or the elevator is called to the other floor.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 14
I have italicized the nouns in this narrative the first time the noun is seen.
I have not mentioned the required elevator's car alarm button.
Entity Names:

Building

Passenger

Elevator Door

Floor(s) m`

Elevator car

Floor's recall button

Elevator car's "other floor" button

Floor's "Car Called" display

Elevator car's bell

Elevator car's alarm button
Identify object behavior
These names likely represent classes that we will need to model.

Building – The Building is outside the simulation, hence the simulation does not
model the Building.
o has one Elevator object
o has two Floor object
o has one clock object

Passenger
o may press floor's elevator recall button
o enters car
o presses car start button
o exits car

Elevator car
o knows which floor it is on.
o responds to "start button" press by moving from one floor to another
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 15
o Emergency stop/alarm press

Floor
o Call Button, – per floor, causes elevator car to return to this floor
o Display light, labeled "Car Called", – per floor. "On" when elevator car is
moving towards this floor
o knows whether this is current floor
o knows its floor number
Details Ignored:
car ventilation, illumination
safety devices such as limit switches and door interlocks
detectors for smoke and high temperature
queuing issues: number of persons waiting for the elevator
There are separate doors into the shaft and into the car, but these open together
Identify the interactions between the objects.

The Floor object
o sends "start" message to the Elevator Car upon "Car Recall" button press.
o updates its display in response to Car notification that the car is in motion.

The Elevator Car object responds to "start" message by
o signaling the current floor to close its door
o starting elevator car
o signaling destination floor to turn elevator called light on
o moving car from current floor to the other floor,
o stopping car
o signaling destination floor to turn elevator called light off
o opening door

The Elevator Car object responds to pressing the
o "Other floor" button by sending its "Recall" message to itself.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 16
o "Alarm/Emergency Stop" button by setting the emergency brake and
sounding an alarm.
Identify state to be maintained to control the elevators.
This may require some coding attempts.

Floor
o display on each floor (light, either on or off, labeled "Car Called")

Elevator Car
o direction – up or down
o running or stopped
o floor (1 or 2)
UML Diagrams
At this point, we need to go to UML diagrams for the objects. There will be an
ElevatorCar class, a Floor class and a Clock class. We list objects and denote interactions
with arrows of the form
to denote the interaction, as UML directs.
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 17
clock
- time : int
+ getTime( ) : int
+ click( ) : void
Timing
car
– direction : enum Direction{ON, FF}
– currentFloor: int
– isMoving : Boolean
+ start ( ) : void
+ pressStartButton( ) : void
+ emergencyStopAlarm( ) : void
toggleCarCalledDisplay
toggleCarCalledDisplay
pressCallButton
pressCallButton
floor [1]
- carCalledDisplay : enum {ON OFF}
floor [2]
- carCalledDisplay : enum {ON OFF}
+ toggleCarCalled( ) : void
+ pressCallButton( ) : void
+ toggleCarCalled( ) : void
+ pressCallButton( ) : void
Remarks:
Here are some details that are not included in the above development but were imposed
by C++ protection model. The elevator car needs to know what the current floor is, and
either floor needs to have some access to the elevator car to be able to start the car. I
gave the ElevatorCar class a pointer to the current floor object, and references to each of
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 18
the floors in the simulation. I gave the Floor class a reference to the ElevatorCar object.
This provides sufficient coupling to enable this solution to the problem to work.
I relearned, for at least the third time, that when you declare a forward reference to a
class, C++ allows only a reference or a pointer to an object of a class that has been
declared forward. C++ will not allow you to declare a class or a function member to be a
friend of another class until the definition of the class to be declared friend has been seen.
My code, and a trial run follow.
//This is the file ch20prog4.cpp
//This is the simulation of a one elevator, two floor system for
//Chapter 20, programming Problem 4.
//
#include <iostream>
enum CarCalledLight {ON, OFF};
enum Direction {UP, DOWN};
enum DoorPosition {CLOSED, OPEN};
class Floor; //a forward declaration.
class ElevatorCar
{
public:
ElevatorCar(Floor& firstFloor, Floor & secondFloor);
void pressStartButton();
// Physical button on car, calls
start()
void start(Floor& currentFloor); // call to actually start the car
void emergencyStopAlarm() const;
const Floor& getCurrentFloor();
private:
void toggleDirection();
Direction direction;
bool motorIsRunning;
Floor* currentFloor;
Floor& floor1;
Floor& floor2;
};
void ElevatorCar::emergencyStopAlarm() const
{
std::cout << "EMERGENCY SIGNAL SENT TO BUILDING MANAGER AND ELEVATOR
COMPANY\n";
}
class Floor
{
public:
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 19
Floor(int floorNumber, ElevatorCar&);
void carCalledDisplayLightToggle();
void pressCallButton();
void closeDoor();
void openDoor();
int getFloorNumber() const;
friend void ElevatorCar::start(Floor&);
private:
DoorPosition door;
CarCalledLight light;
const int THIS_FLOOR_NUMBER;
ElevatorCar & car;
};
int Floor::getFloorNumber() const
{
return THIS_FLOOR_NUMBER;
}
void Floor::carCalledDisplayLightToggle()
{
if(light == ON)
{
std::cout << "Turning CarCalled Display on floor "
<< THIS_FLOOR_NUMBER
<< " OFF" << std::endl;
light = OFF;
}
else
{
std::cout << "Turning CarCalled Display on floor "
<< THIS_FLOOR_NUMBER << " ON"
<< std::endl;
light = ON;
}
}
ElevatorCar::ElevatorCar(Floor& first, Floor& second)
: currentFloor(&first), direction(DOWN),
motorIsRunning(OFF), floor1(first),
floor2(second)
{
std::cout << "Elevator car created with floor numbers"
<< floor1.getFloorNumber()
<< " and "
<< floor2.getFloorNumber()
<< std::endl;
}
void ElevatorCar::pressStartButton()
{
std::cout << "Just pressed Start Button. Current floor is "
<< currentFloor->getFloorNumber()
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 20
<< std::endl;
start(*currentFloor);
}
void Floor::pressCallButton()
{
car.pressStartButton();
}
Floor::Floor(int floorNumber, ElevatorCar& thisCar)
: door(CLOSED),light(OFF),
THIS_FLOOR_NUMBER(floorNumber),
car(thisCar)
{ //Deliberately empty
}
void ElevatorCar::toggleDirection()
{
if(direction == UP)
direction= DOWN;
else
direction = UP;
}
void ElevatorCar::start(Floor& floor)
{
using std::cout; using std::endl;
cout << "In Start function, with the Elevator car at floor "
<< currentFloor->THIS_FLOOR_NUMBER
<< endl;
currentFloor->closeDoor();
cout << "Starting elevator car" << endl;
toggleDirection();
motorIsRunning = true;
currentFloor = (currentFloor == &floor1) ? &floor2 : &floor1;
currentFloor->carCalledDisplayLightToggle();
motorIsRunning = false;
cout << "Stopping elevator car" << endl;
currentFloor->carCalledDisplayLightToggle();
cout << "Elevator is at floor " << currentFloor->THIS_FLOOR_NUMBER <<
endl;
currentFloor->openDoor();
}
const Floor& ElevatorCar::getCurrentFloor()
{
return *currentFloor;
}
void Floor::openDoor()
{
std::cout << "Opening Door" << std::endl;
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
door = OPEN;
}
void Floor::closeDoor()
{
std::cout << "Closing Door" << std::endl;
door = CLOSED;
}
class Clock
{
public:
Clock();
void click();
int getTime();
private:
int time;
};
Clock::Clock():time(0)
{
//Deliberately empty
}
void Clock::click()
{
time++;
}
int Clock::getTime()
{
return time;
}
class Building
{
public:
Building();
void simulateElevator(int timeToRun);
private:
Floor firstFloor;
Floor secondFloor;
ElevatorCar car;
Clock clock;
};
Building::Building() : firstFloor(1, car),
secondFloor(2, car),
car(firstFloor, secondFloor)
{
std::cout << "Building constructed" << std::endl;
}
Page 21
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 22
void Building::simulateElevator(int runTime)
{
using std::cout; using std::endl;
int time = 0;
while(time < runTime)
{
time = clock.getTime();
cout << "Time: " << time << endl;
clock.click();
cout << "Pressing Start Button " << endl;
car.pressStartButton();
cout << endl;
}
cout <<
<<
<<
<<
"Pressing call button from a floor that is not"
"the current floor \nThe Current floor is "
car.getCurrentFloor().getFloorNumber()
endl;
if(1 == car.getCurrentFloor().getFloorNumber())
{
cout << "pressing second floor call button" << endl;
secondFloor.pressCallButton();
}
else
{
cout << "pressing first floor call button" << endl;
firstFloor.pressCallButton();
}
cout <<
<<
<<
<<
"Again, pressing call button from a floor that is not"
"the current floor \nThe Current floor is "
car.getCurrentFloor().getFloorNumber()
endl;
if(1 == car.getCurrentFloor().getFloorNumber())
{
secondFloor.pressCallButton();
}
else
{
cout << "pressing first floor call button" << endl;
firstFloor.pressCallButton();
}
}
int main()
{
Building bank;
bank.simulateElevator(4);
return 0;
}
Here is a Trial run:
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Elevator car created with floor numbers1 and 2
Building constructed
Time: 0
Pressing Start Button
Just pressed Start Button. Current floor is 1
In Start function, with the Elevator car at floor 1
Closing Door
Starting elevator car
Turning CarCalled Display on floor 2 ON
Stopping elevator car
Turning CarCalled Display on floor 2 OFF
Elevator is at floor 2
Opening Door
Time: 1
Pressing Start Button
Just pressed Start Button. Current floor is 2
In Start function, with the Elevator car at floor 2
Closing Door
Starting elevator car
Turning CarCalled Display on floor 1 ON
Stopping elevator car
Turning CarCalled Display on floor 1 OFF
Elevator is at floor 1
Opening Door
Time: 2
Pressing Start Button
Just pressed Start Button. Current floor is 1
In Start function, with the Elevator car at floor 1
Closing Door
Starting elevator car
Turning CarCalled Display on floor 2 ON
Stopping elevator car
Turning CarCalled Display on floor 2 OFF
Elevator is at floor 2
Opening Door
Time: 3
Pressing Start Button
Just pressed Start Button. Current floor is 2
In Start function, with the Elevator car at floor 2
Closing Door
Starting elevator car
Turning CarCalled Display on floor 1 ON
Stopping elevator car
Turning CarCalled Display on floor 1 OFF
Elevator is at floor 1
Opening Door
Time: 4
Pressing Start Button
Just pressed Start Button. Current floor is 1
In Start function, with the Elevator car at floor 1
Closing Door
Page 23
Instructor’s Resource Manual for Savitch Absolute C++ 03/06/16
Chapter 20 Patterns and UML
Page 24
Starting elevator car
Turning CarCalled Display on floor 2 ON
Stopping elevator car
Turning CarCalled Display on floor 2 OFF
Elevator is at floor 2
Opening Door
Pressing call button from a floor that is not the current floor
Current floor is 2
pressing first floor call button
Just pressed Start Button. Current floor is 2
In Start function, with the Elevator car at floor 2
Closing Door
Starting elevator car
Turning CarCalled Display on floor 1 ON
Stopping elevator car
Turning CarCalled Display on floor 1 OFF
Elevator is at floor 1
Opening Door
Again pressing call button from a floor that is not the current floor
Current floor is 1
Just pressed Start Button. Current floor is 1
In Start function, with the Elevator car at floor 1
Closing Door
Starting elevator car
Turning CarCalled Display on floor 2 ON
Stopping elevator car
Turning CarCalled Display on floor 2 OFF
Elevator is at floor 2
Opening Door
*/
5. Elevator: Two elevators, 10 floors.
No notes are provided. However, please pass this word advice to your students: "This is
not a trivial problem. Do Problem 4 first!"
Download