for RuBoard |
With the abstractions Reservable , Reservation , and Broker already in place, it now becomes very easy to implement a reservation system for a particular kind of reservable, such as a Hotel . Figure 4-2 illustrates our inheritance hierarchy. Hotel derives from Reservable , HotelReservation derives from Reservation , and HotelBroker derives from Broker .
In this section we will examine key pieces of the implementation of the case study, which is in the CaseStudy folder for this chapter.
Before proceeding with our code walkthrough, it would be a good idea to build and run the case study. The program TestBroker.exe is a console application. By typing "help" at the command prompt, you can obtain a list of commands:
Enter command, quit to exit H> help The following commands are available: hotels shows all hotels in a city all shows all hotels cities shows all cities add adds a hotel book book a reservation bookings show all bookings register register a customer email change email address show show customers quit exit the program H>
Experiment with this program until you have a clear understanding of its various features.
HotelReservation is a simple class derived from Reservation . The code is in the file hotelbroker.cs . It adds some additional public fields and provides the property ArrivalDate as a more meaningful wrapper around the generic Date field of the base class.
public class HotelReservation : Reservation { public int CustomerId; public string HotelName; public string City; public DateTime DepartureDate; public DateTime ArrivalDate { get { return Date; } set { Date = value; } } }
The heart of the implementation is the HotelBroker class, derived from Broker . The code is also in the file hotelbroker.cs .
public class HotelBroker : Broker { private const int MAXDAY = 366; private const int MAXUNIT = 10; private const int MAXCITY = 5; static private int nextCity = 0; private string[] cities; public HotelBroker() : base(MAXDAY, MAXUNIT) { cities = new String[MAXCITY]; AddHotel("Atlanta", "Dixie", 100, 115.00M); AddHotel("Atlanta", "Marriott", 500, 70.00M); AddHotel("Boston", "Sheraton", 250, 95.00M); } ...
There are constants for various array definitions and a new array to hold the cities. The constructor passes some array definitions to the base class, initializes the cities array, and adds some starter hotels as test data.
The next part of the code defines a NumberCity property and provides a method to add a hotel.
public int NumberCity { get { return nextCity; } } public string AddHotel(string city, string name, int number, decimal cost) { if (FindId(city, name) != -1) return "Hotel is already on the list"; Hotel hotel = new Hotel(city, name, number, cost); AddUnit(hotel); AddCity(city); return "OK"; } ...
Private helper functions are provided to find the id of a hotel and to add a city to the list of cities. A city can be added only if it is not already on the list; duplicates are not permitted.
private int FindId(string city, string name) { for (int i = 0; i < NumberUnits; i++) { Hotel hotel = (Hotel) units[i]; if ((hotel.City == city) && (hotel.HotelName == name)) return hotel.Id; } return -1; } private void AddCity(string city) { // check if city already on list, add if not if (!Contains(city)) cities[nextCity++] = city; } private bool Contains(string city) { for (int i = 0; i < NumberCity; i++) { if (cities[i] == city) return true; } return false; }
Methods are provided to show all the hotels, all the hotels in a given city, and to show the cities. You may wish to examine this code for a review of formatting in C#.
We finally come to the key method Reserve , which is used to book a hotel reservation.
public ReservationResult Reserve(int customerId, string city, string name, DateTime dt, int numDays) { int id = FindId(city, name); if (id == -1) { ReservationResult result = new ReservationResult(); result.ReservationId = -1; result.Comment = "Hotel not found"; return result; } HotelReservation res = new HotelReservation(); res.UnitId = id; res.CustomerId = customerId; res.HotelName = name; res.City = city; res.ArrivalDate = dt; res.DepartureDate = dt + new TimeSpan(numDays, 0, 0, 0); res.NumberDays = numDays; return Reserve(res); }
The code in this class is very simple, because it relies upon logic in the base class Broker . An error is returned if the hotel cannot be found on the list of hotels. Then a HotelReservation object is created, which is passed to the Reserve method of the base class. We create the reservation object in the derived class, because we are interested in all the fields of the derived HotelReservation class, not just the fields of the base Reservation class. We have previously used the DateTime structure, and we now use the TimeSpan structure in calculating the departure date by adding the number of days of the stay to the arrival date. This calculation relies on the fact that the + operator is overloaded in the DateTime structure.
No reservation system can exist without modeling the customers that use it. The Customers class in the file customer.cs maintains a list of Customer objects. Again we use an array as our representation. This code has very similar structure to code dealing with hotels, and so we show it only in outline form, giving the data structures and the declarations of the public methods and properties.
// Customer.cs namespace OI.NetCs.Acme { using System; public class Customer { public int CustomerId; public string FirstName; public string LastName; public string EmailAddress; static private int nextCustId = 1; public Customer(string first, string last, string email) { CustomerId = nextCustId++; FirstName = first; LastName = last; EmailAddress = email; } } public class Customers { private Customer[] customers; static private int nextCust = 0; public Customers(int MaxCust) { customers = new Customer[MaxCust]; RegisterCustomer("Rocket","Squirrel", "rocky@frosbitefalls.com"); RegisterCustomer("Bullwinkle", "Moose", "moose@wossamotta.edu"); } public int NumberCustomers ... public int RegisterCustomer(string firstName, string lastName, string emailAddress) ... public void ShowCustomers(int customerId) ... public void ChangeEmailAddress(int id, string emailAddress) ...
All case study code is in the namespace OI.NetCs.Acme . All of the files defining classes begin with a namespace directive. There is a corresponding using directive, which you will see in the file TestHotel.cs .
// Customer.cs namespace OI.NetCs.Acme { ...
The TestHotel class in the file TestHotel.cs contains an interactive program to exercise the hotel and customer classes, supporting the commands shown previously where we suggested running the case study. There is a command loop to read in a command and then exercise it. There is a big try block around all the commands with a catch handler afterward. Note the using statement to gain access to the namespace.
// TestHotel.cs using System; using OI.NetCs.Acme; public class TestHotel { public static void Main() { const int MAXCUST = 10; HotelBroker hotelBroker = new HotelBroker(); Customers customers = new Customers(MAXCUST); InputWrapper iw = new InputWrapper(); string cmd; Console.WriteLine("Enter command, quit to exit"); cmd = iw.getString("H> "); while (! cmd.Equals("quit")) { try { if (cmd.Equals("hotels")) { string city = iw.getString("city:"); hotelBroker.ShowHotels(city); } else if (cmd.Equals("all")) hotelBroker.ShowHotels(); ... else hotelhelp(); } catch (Exception e) { Console.WriteLine( "Exception: {0}", e.Message); } cmd = iw.getString("H> "); } } private static void hotelhelp() { Console.WriteLine( "The following commands are available:"); ... } }
for RuBoard |