Download:
Here is Horstman's code. However - STL elements copy objects (not
pointers to objects) so polymorphism does not work here. Code such
as event_queue.cpp
looks
at the amount of copying going on.
bank1.cpp
/**************************************************************************** ** COPYRIGHT (C): 1994 Cay S. Horstmann. All Rights Reserved. ** PROJECT: Mastering Object-Oriented Design ** FILE: bank1.cpp ** PURPOSE: A bank simulation ** VERSION 1.0 ** LANGUAGE: Borland C++ 3.0 ** TARGET: IBM PC ** PROGRAMMER: Cay Horstmann (CSH) ** START DATE: 4-30-92 (CSH) ** UPDATE HISTORY: ****************************************************************************/ /* IMPORT ******************************************************************/ #include <math.h> #include "chiarray.h" #include "chiqueue.h" #include "chiprioq.h" /* TYPES *******************************************************************/ typedef double Time; // measured in minutes /*-------------------------------------------------------------------------*/ class Event /* PURPOSE: An event that is scheduled for execution at some time */ { public: Event(Time t); virtual void process() = 0; Time time() const; virtual ~Event() {} private: Time _time; }; /*-------------------------------------------------------------------------*/ class Arrival : public Event /* PURPOSE: Customer arrives at bank */ { public: Arrival(Time); virtual void process(); }; /*-------------------------------------------------------------------------*/ class Departure : public Event /* PURPOSE: Customer departs from teller */ { public: Departure(Time, int teller); virtual void process(); private: int _teller; }; /*-------------------------------------------------------------------------*/ class Customer /* PURPOSE: A bank customer */ { public: Customer(Time t); Time arrival_time() const; private: Time _arrival_time; }; /*-------------------------------------------------------------------------*/ class BankStatistics /* PURPOSE: Gather statistics to compute averages */ { public: BankStatistics(); void add(Time t); void print() const; double average_time() const; private: int _ncust; Time _total_time; }; /*-------------------------------------------------------------------------*/ class Bank /* PURPOSE: Simulation of customer traffic in a bank */ { public: Bank(); void add(Customer*); void add_to_teller(int teller, Customer*); Customer* remove(int teller); void print() const; private: enum { NTELLER = 5 }; Chi_PtrArray<Customer> _teller; Chi_Queue<Customer*> _cust_queue; }; /* GLOBALS *****************************************************************/ const Time INTERARRIVAL = 1.0; // 1 minute const Time AVG_PROCTIME = 5.0; // 5 minutes static int event_compare(const Event* a, const Event* b); Chi_PtrPriorityQueue<Event> event_queue(event_compare); Time now; Bank bank; BankStatistics stat; /* FUNCTIONS ***************************************************************/ static double expdist(double mean) /* PURPOSE: Compute exponentially distributed random numbers RECEIVES: mean - the mean of the number sequence RETURNS: a random number */ { double r = rand(); r /= RAND_MAX; return -mean*log(r); } /*.........................................................................*/ static int event_compare(const Event* a, const Event* b) /* PURPOSE: compare two events by their time stamp RECEIVES: a, b - pointers to two events RETURNS: -1 if a is scheduled earlier than b, 0 if they are scheduled at the same time, 1 otherwise */ { Time d = a->time() - b->time(); return (d > 0) - (d < 0); } /*.........................................................................*/ void main() { const Time STARTTIME = 9 * 60; // 9 a.m. const Time ENDTIME = 17 * 60; // 5 p.m. now = STARTTIME; event_queue.insert(new Arrival(now)); while (event_queue.length() > 0 && now <= ENDTIME) { Event* event = event_queue.remove(); now = event->time(); event->process(); delete event; bank.print(); } stat.print(); } /*-------------------------------------------------------------------------*/ Event::Event(Time t) /* RECEIVES: t - the execution time of this event */ : _time(t) {} /*.........................................................................*/ Time Event::time() const /* RETURNS: the time at which the event is to be executed */ { return _time; } /*-------------------------------------------------------------------------*/ Arrival::Arrival(Time t) /* RECEIVES: t - the time at which the arrival will occur */ : Event(t) {} /*.........................................................................*/ void Arrival::process() /* PURPOSE: process an arrival event */ { Customer* c = new Customer(now); bank.add(c); Time t = expdist(INTERARRIVAL); event_queue.insert(new Arrival(now + t)); } /*-------------------------------------------------------------------------*/ Departure::Departure(Time t, int teller) /* RECEIVES: t - the time at which the departure will occur teller - teller position */ : Event(t), _teller(teller) {} /*.........................................................................*/ void Departure::process() /* PURPOSE: process a departure event */ { Customer* c = bank.remove(_teller); delete c; } /*-------------------------------------------------------------------------*/ Customer::Customer(Time t) /* RECEIVES: the time at which the customer entered the bank */ : _arrival_time(t) {} /*.........................................................................*/ Time Customer::arrival_time() const /* RETURNS: the time at which the customer entered the bank */ { return _arrival_time; } /*-------------------------------------------------------------------------*/ BankStatistics::BankStatistics() : _ncust(0), _total_time(0) {} /*.........................................................................*/ void BankStatistics::add(Time t) /* PURPOSE: add another customer who is leaving the bank to the statistics RECEIVES: t - the time the customer left */ { _ncust++; _total_time += t; } /*.........................................................................*/ double BankStatistics::average_time() const /* PURPOSE: returns the average time the customers spent in the bank */ { if (_ncust == 0) return 0; else return _total_time/_ncust; } /*.........................................................................*/ void BankStatistics::print() const /* PURPOSE: print a summary of the gathered statistics */ { cout << _ncust << " customers. Average time " << average_time() << " minutes." << endl; } /*-------------------------------------------------------------------------*/ Bank::Bank() : _teller(1, NTELLER) {} /*.........................................................................*/ void Bank::add(Customer* c) /* PURPOSE: Add a customer to the bank RECEIVES: c - the customer */ { for (int i = 1; i <= NTELLER; i++) if (_teller[i] == 0) { add_to_teller(i, c); return; } _cust_queue.insert(c); } /*.........................................................................*/ void Bank::add_to_teller(int i, Customer* c) /* PURPOSE: add customer to an empty teller RECEIVES: i - teller position c - the customer to add */ { CHI_ASSERT_PRECOND(_teller[i] == 0); _teller[i] = c; Time t = expdist(AVG_PROCTIME); event_queue.insert(new Departure(now + t, i)); } /*.........................................................................*/ Customer* Bank::remove(int i) /* PURPOSE: remove customer from teller RECEIVES: i - teller position */ { Customer* c = _teller[i]; _teller[i] = 0; stat.add(now - c->arrival_time()); if (_cust_queue.length() > 0) add_to_teller(i, _cust_queue.remove()); return c; } /*.........................................................................*/ void Bank::print() const /* PURPOSE: Print teller and queue */ { for (int i = 1; i <= NTELLER; i++) cout << (_teller[i] == 0 ? '.' : 'C'); cout << '<'; int q = _cust_queue.length(); for (int j = 1; j <= q; j++) cout << 'C'; cout << endl; } /***************************************************************************/
This does not compile without chilb105
routines.
Maintained by John Loomis, updated Wed Feb 21 17:13:39 2007