CS 250 Computer Programming and Problem Solving - FALL 1998 |
---|
[ Home | Syllabus | Notes | Glossary | CS250 WEB Version Home Page ]
Design Notes: Or why I change the examples in the book
FixedString Class
Why did I change the FString example in the book?
Show the beauty of overloading the comparison
operators
One of the big attractions to object oriented programming is the ability for the
programmer to create objects which have all the advantages of the built-in data types.
Mainly this means the ability to overload the operators.
Since we already know how to overload the I/O operators, why not do it right?
Doctor Appointment Schedule
This is an interesting and complicated example.
There are many reasonable solutions
What I don't like about the design in the book.
inline functions defined in the header file
the Number of Doctors (const NumDoctors) is global to all objects (avoid global data)
doctorName is an static array common the the
class instead of belonging to an object
class static data is something we don't need to know about yet
and its use in this case is complicated and confusing (it is possible to get out
of sync on the number of doctorNames and the number of Doctors)
Access to the doctor's name is NOT through the doctor object but by using an index in this array
Scenarios
It is difficult to specify your classes without knowing how they will be used
A scenario is a particular way of using a set of objects. Typically a scenario is described in English and explains how the system and its objects will be used. This often points out functions that are needed (either in the classes as member functions) or in the system in general.
Let's examine a few scenarios for the Doctor Appointment Problem:
Scenario 1:
Scenario 2:
Scenario 3:
Scenario 4:
Scenario 5:
Of course there are many other scenarios: we want the most critical ones first
Going through each scenario will bring up issues to be resolved and problems to be solved.
For instance in scenario 1:
In solving these problems, various design decisions will be made and responsibilites assigned to the objects we identified earlier.
Where to go Next?
Pick any scenario (say 1 which is probably the most common) and begin to make decisions which assign functions and properties to the objects mentioned in this scenario.
So we have a bunch of HAS-A relationships between these objects.
But how exactly should these relationships be expressed? for example:
Another issue: should this information be crossed referenced? For exmaple,
Now What?
Once we have a reasonable understanding of the objects and their relationship, we can begin to design them. There are a number of basic approaches
Top Down: start with the main program and main outer object (Scheduler in this case) and begin designing.
Bottom Up: start with those objects which have no
other objects as member (stand-alone objects) or those which have a minimum number of
included objects.
Remember it is possible to have circular relationships. a Doctor can
have Patients and Patients can have Doctors.
Riskest First: tackle those parts which are the most unknown or which are most critical. If you can't get these right, the rest is for naught. If you have to give up and start over, this approach makes the minimum investment in time.
Incremental Design with Easiest components first: gains experience with problem and gets a running system the fastest.
Increment Design which covers the most common scenarios first: This will give a useful system early in the cycle.
I'll try a top down, incremental design to cover a
simplified scenario 1.
Simplified because only one doctor.
//###################### // Scheduler is responsible for making appointments with patients // and recording them in the doctor's daily schedule // and Printing out these schedules // keeps a reference to all doctors for this purpose //###################### class Scheduler { public: Scheduler( Doctor * docs, unsigned NumDoctors); // Scheduler keeps track of appointments for all doctors // A list of doctors is passed and a reference to this list is kept // in this object void PrintAllAppointments( const char * fileName ); // PRE: fileName is a legtimate file name // POST: the daily schedule of all doctors is printed to "fileName" bool ScheduleOneAppointment(); // Makes an appointment for one patient //POST: If there is another patient, schedules an appoitment for that patient // and returns true // else returns false (meaning, that the day is over - go home) void ScheduleAllAppointments(); // runs all day scheduling appointments // returns when all patients have be scheduled for this day private: Doctor * doctors; // points to first element in array of doctors // notice that there is only one copy of the doctor object, but we can // refer to it using the pointer and so can update the doctor/s schedule // we could have made a copy of the doctor objects - // but then they could not be accessed or changed outside (consistently) unsigned NumDoctors; // keeps size of array of Doctors };
//................ Scheduler ................. // Initialize // array of doctors from a file. Scheduler::Scheduler( Doctor * docs, unsigned num ) { doctors = docs; NumDoctors = num; ifstream dnameFile( "doctors.txt" ); if( !dnameFile ) { cout << "Cannot open input file! Aborting program.\n"; abort; } FixedString temp; for(unsigned i = 0; i < NumDoctors; i++) { dnameFile >> temp; doctors[i].SetName( temp ); } } // Write each doctor's list of appointments, // showing time and patient name for each. void Scheduler::PrintAllAppointments(const char * fileName) { ofstream ofile( fileName ); if( ofile ) for(unsigned i = 0; i < NumDoctors; i++) doctors[i].ShowAppointments( ofile ); } void Scheduler::ScheduleAllAppointments() { while( ScheduleOneAppointment() ) continue; } // Choose a doctor, input patient name, and // ask for a particular time slot. Make the // appointment, and display the results. int Scheduler::ScheduleOneAppointment() { // Get patient name, let patient request a doctor. Patient aPatient; aPatient.InputName(); // Show patient list of doctor's names and let patient choose one. //unsigned doctorNum = aPatient.ChooseDoctor(); doctorNum = 0; //?????? for testing always choose the first doctor Doctor & theDoc = doctors[doctorNum]; while( !aPatient.IsScheduled() ) { // Patient chooses a time slot. Construct an appointment // from the time slot, doctor number, and patient name. TimeSlot aTime = aPatient.ChooseTimeSlot( theDoc ); Appointment app( aTime, doctorNum, aPatient ); // Try to schedule the patient for a particular time // slot with the chosen doctor. If successful, add the // appointment time to the patient's record; if not, // display an error message. if( theDoc.AddToSchedule( app )) aPatient.SetAppointment( app ); else cout << "Sorry, Dr. " << theDoc.GetLastName() << " is not available at that time. " << endl; } cout << aPatient; return getYN("Continue?"); }