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!"