Скачиваний:
64
Добавлен:
15.03.2015
Размер:
4.31 Mб
Скачать

Chapter 5 • YOUR FIRST OBJECT-ORIENTED C# PROGRAM 115

as one expression. The assignment operator = acts on this latter expression and the expression mySum. Expressions are often nested inside each other to form hierarchies of expressions, as in the previous example.

Operators can be divided into the following categories—assignment, arithmetic, unary, equality, relational, logical, conditional, shift, and primary operators.

We will spend more time on operators in later chapters, but the following is a quick summary of the operators you have encountered so far:

Assignment operator (=)—Causes the operand on its left side to have its value changed to the expression on the right side of the assignment operator as in

29:sumTotal = a + b;

where a + b can be regarded as being one operand.

• Binary arithmetic operators (+ and *)—The following example

a * b

multiplies a and b without changing their values.

Concatenation operator (+)—Concatenates two strings into one string.

Equality operator (==)—Compares two expressions to test whether they are equal. For example,

leftExpression == rightExpression

will only be true if the two expressions are equal; otherwise, it is false.

Keywords

Appendix C at www.samspublishing.com lists all 77 different keywords of C#. We have so far met the keywords if, class, public, static, void, string, int, and return. The syntax (language rules) of the operators and separators combined with the keywords form the definition of the C# language.

Some Thoughts on Elevator Simulations

The C# program presented after the following case study is a first attempt (prototype) to implement an object-oriented elevator simulation. The case study introduces a few goals, problems, and solutions of a simple elevator simulation and attempts to put you in the right frame of mind for the following practical C# example. It is also meant as a reminder of our encapsulation discussion in the beginning of Chapter 3.

116 C# PRIMER PLUS

Concepts, Goals and Solutions in an Elevator Simulation Program: Collecting Valuable Statistics for Evaluating an Elevator System

This case study looks at a strategy for collecting important information from a particular elevator simulation to answer the question, “Is the elevator system that we are simulating performing its task of transporting passengers between various floors properly?” In other words, if we took a real elevator system, extracted all its relevant characteristics, and turned it into a computer simulation, how well would this system perform?

Statistics

A numerical fact or datum, especially one computed from a sample, is called a statistic.

Statistics is the science that deals with the collection, classification, analysis, and interpretation of numerical facts or data, and that, by use of mathematical theories of probability, imposes order and regularity on aggregates of more or less disparate elements.

The term statistics is also used to refer to the numerical facts or data themselves.

Two statistics considered important by most elevator travelers when rating an elevator system are

The time a typical person has to wait on a floor after having pressed the button to call the elevator

The average time it takes to travel one floor

An attempt to collect these numbers from an elevator simulation could be done as follows.

Because the Person objects are “traveling” through the elevator system, it is ultimately these objects that the Elevator objects must service. Consequently, the Person objects will “know” how well the system is working and are able to collect some of the essential statistics required. An analogous strategy in the real world would be to interview the users of the elevator system and gather some of their elevator system experiences.

Each Person object of the elevator simulation program could be implemented to have a couple of instance variables keeping track of its total waiting time outside the elevator (to answer the first bullet) and an average traveling time per floor (addressing the second bullet). They would give a good indication of how well the elevator system is working and be part of the statistics collected for each simulation. We could call these variables totalWaitingTime and averageFloorTravelingTime.

Calculating totalWaitingTime would require a method located inside Person containing instructions to start the computer’s built-in stopwatch every time the person has “pressed a button” on a particular Floor object calling an elevator. As soon as the Elevator object “arrives,” the stopwatch is stopped and the time is added to the current value of totalWaitingTime.

private.

Chapter 5 • YOUR FIRST OBJECT-ORIENTED C# PROGRAM 117

Similarly, the averageFloorTravelingTime is calculated by another method inside Person starting the stopwatch as soon as the Person object has “entered” the Elevator object. When the Person has reached its “destination,” the stopwatch is stopped and the time divided by the number of floors “traveled” to get the average traveling time per floor. This result is stored in a list together with other averageFloorTravelingTime sizes. When the final averageFloorTravelingTime statistic needs to be calculated, a method will calculate the average of the numbers stored in the list.

All these calculations involving starting and stopping stopwatches, summing numbers, calculating averages, and so on are not of any interest to other objects in the simulation, and they would complicate matters unduly for other programmers were they exposed to them. Consequently, we should hide all the methods involved here by declaring them to be

Each Person object must also be able to report its totalWaitingTime and averageFloorTravelingTime sizes. We can do this through two public methods arbitrarily named getTotalWaitingTime and getAverageFloorTravelingTime. Any other object calling any of these two methods will receive the corresponding statistic.

Another programmer who is also working on this project is writing a class to collect the important statistics of each simulation. He or she calls this class StatisticsReporter. He or she must ensure that all Person objects are “interviewed” at the end of a simulation by letting the StatisticsReporter collect their totalWaitingTime and averageFloorTravelingTime statistics. The StatisticsReporter can now simply do this by calling the getTotalWaitingTime and getAverageFloorTravelingTime methods of each Person object involved in a particular simulation.

To summarize:

getTotalWaitingTime and getAverageFloorTravelingTime are part of an interface that is hiding or encapsulating all the irrelevant complexities for our happy programmer of the StatisticsReporter.

Likewise, the instance variables of the Person objects should be hidden by declaring them private. This prevents any other objects, including the StatisticsReporter, from mistakenly changing any of these sizes. In other words, the getTotalWaitingTime and getAverageFloorTravelingTime methods “cover,” by means of encapsulation, the instance variables totalWaitingTime and averageFloorTravelingTime as a protective wrapper by allowing only the StatisticsReporter to get the values of these and not to set them.

Object-Oriented Programming: A Practical

Example

So far, our discussion about object-oriented programming has been somewhat theoretical. We have discussed the difference between classes and objects and how objects need to be instantiated before they can actually perform any actions. You have seen a couple of simple classes in Listings 3.1 of Chapter 3 and 4.1 of Chapter 4, but they didn’t contain any real objects; they

118 C# PRIMER PLUS

were passive containers only created to hold the Main method. Actually, none of these programs can be regarded as being particularly object-oriented. Because they only have methods containing sequences of statements one executed after the other, they resemble programs written in the procedural programming style.

By merely adding plenty of methods and statements to the SimpleCalculator class of Listing 4.1, it would be possible, albeit extremely cumbersome, to write a valid and full-blown sophisticated spreadsheet application without ever being concerned about writing any other classes, learning any theoretical object-oriented principles, or ever using any mentionable object-ori- ented C# features. The structure of this program would be closer to a program written in a procedural language like C or Pascal than it would to a typical object-oriented C# program.

Conversely and surprisingly, it would also be possible to write an object-oriented program in C or Pascal, but it would be awkward because these languages, as opposed to C#, do not have any built-in support for this paradigm.

To make our previous object-oriented discussions more practical and to avoid the risk of constructing a non-object-oriented full-size spreadsheet program, I have provided an example illustrating a couple important C# features closely related to our theoretical discussion about classes, objects, and instantiation.

Presenting SimpleElevatorSimulation.cs

Listing 5.1 contains the source code for a simple elevator simulation program. Its goal is to illustrate what a custom-made object looks like in C# and how it is instantiated from a custom written class. In particular, it shows how an Elevator object is created and how it calls a method of the Person object named NewFloorRequest and triggers the latter to return the number of the requested “floor,” enabling the Elevator to fulfill this request.

Many abstractions were made during the design stage of the source code in Listing 5.1, allowing us to make the program simple and be able to concentrate on the essential object-oriented parts of the source code.

The following is a brief description of the overall configuration of the elevator’s system used for this simulation, highlighting the major differences to a real elevator system.

The Building class has one Elevator object called elevatorA.

One Person object residing inside the passenger variable is “using” elevatorA.

The Elevator object can “travel” to any “floor” that is within the range specified by the int type (–2147483648 to 2147483647). However, a Person object is programmed to randomly choose floors between 1 and 30.

The elevator will instantly “travel” to the “destination floor.”

The “movements” of elevatorA will be displayed on the console.

After the passenger has “entered” elevatorA, “he” or “she” will stay in elevatorA throughout the simulation and simply choose a new floor whenever a previous request has been satisfied.

Chapter 5 • YOUR FIRST OBJECT-ORIENTED C# PROGRAM 119

Only the Elevator, Person, and Building classes are used in this simulation, leaving out Floor, StatisticsReporter, and other classes considered important for a fullblown simulation.

At the end of each simulation, the total number of floors traveled by elevatorA will be displayed on the console. This number could be a very important statistic in a serious elevator simulation.

So, despite the simplicity and high abstraction of this simulation, we are actually able to extract one important statistic from it and, without too many additions, you would be able to create a small but useful simulation enabling the user to gain valuable insights into a real elevator system.

Please take a moment to examine the source code in Listing 5.1. Try first to establish a bigger picture when looking through the code. For example, notice the three class definitions (Elevator, Person and Building) that constitute the entire program (apart from lines 1–4). Then notice the methods defined in each of these three classes and the instance variables of each class.

Note

Recall that the order in which the methods of a class are written in the source code is independent of how the program is executed. The same is true for the order of the classes in your program. You can choose any order that suits your style. In Listing 5.1, I chose to put the class containing the Main method last, and yet Main is the first method to be executed.

Typical output from Listing 5.1 is shown following the listing. Because the requested floor numbers are randomly generated, the “Departing floor” and “Traveling to” floors (except for the first departing floor, which will always be 1) and the “Total floors traveled” will be different on each run of the program.

LISTING 5.1 Source Code for SimpleElevatorSimulation.cs

01: // A simple elevator simulation 02:

03: using System; 04:

05: class Elevator 06: {

07:private int currentFloor = 1;

08:private int requestedFloor = 0;

09:private int totalFloorsTraveled = 0;

10:private Person passenger;

11:

12:public void LoadPassenger()

13:{

14:passenger = new Person();

15:}

120 C# PRIMER PLUS

LISTING 5.1 continued

16:

17:public void InitiateNewFloorRequest()

18:{

19:requestedFloor = passenger.NewFloorRequest();

20:Console.WriteLine(“Departing floor: “ + currentFloor

21:+ “ Traveling to floor: “ + requestedFloor);

22:totalFloorsTraveled = totalFloorsTraveled +

23:Math.Abs(currentFloor - requestedFloor);

24:currentFloor = requestedFloor;

25:}

26:

27:public void ReportStatistic()

28:{

29:Console.WriteLine(“Total floors traveled: “ + totalFloorsTraveled);

30:}

31:}

32:

33:class Person

34:{

35:private System.Random randomNumberGenerator;

37:public Person()

38:{

39:randomNumberGenerator = new System.Random();

40:}

41:

42:public int NewFloorRequest()

43:{

44:// Return randomly generated number

45:return randomNumberGenerator.Next(1,30);

46:}

47:}

48:

49:class Building

50:{

51:private static Elevator elevatorA;

53:public static void Main()

54:{

55:elevatorA = new Elevator();

56:elevatorA.LoadPassenger();

57:elevatorA.InitiateNewFloorRequest();

58:elevatorA.InitiateNewFloorRequest();

59:elevatorA.InitiateNewFloorRequest();

60:elevatorA.InitiateNewFloorRequest();

61:elevatorA.InitiateNewFloorRequest();

62:elevatorA.ReportStatistic();

63:}

64:}

Departing floor: 1 Traveling to floor: 2

Departing floor: 2 Traveling to floor: 24

Chapter 5 • YOUR FIRST OBJECT-ORIENTED C# PROGRAM 121

Departing floor: 24 Traveling to floor: 15

Departing floor: 15 Traveling to floor: 10

Departing floor: 10 Traveling to floor: 21

Total floors traveled: 48

Overall Structure of the Program

Before we continue with the more detailed analysis of the program, look at Figure 5.1. It connects the illustration used in Figure 3.1, shown in Chapter 3, with the concrete C# program of Listing 5.1.

The Elevator and Person classes of Listing 5.1 define abstracted versions of our now familiar counterparts from the real world. They are graphically depicted next to their C# counterparts in Figure 5.1. Each part of the Elevator and Person classes written in the C# source code (indicated by braces) has been linked to its graphical counterpart with arrows. Notice how the public methods of the two classes (the interface) encapsulate the hidden private instance variables. In this case, no private methods were needed.

The Building class has one Elevator, which is represented by its elevatorA instance variable declared in line 51. It also holds the Main method where the application commences. This class is never instantiated in the program. It is used by the .NET runtime to access Main and start the program.

Just as in the previous listings, I will provide a brief explanation of the lines in the source code. Many lines have not been shown because they have already been explained in a previous example.

LISTING 5.2 Brief Analysis of Listing 5.1

05: Begin the definition of a class named Elevator

07:Declare an instance variable called currentFloor to be of type int; setits access level to private and its initial value to 1.

10:Declare passenger to be a variable, which can hold an

object of class Person. The class Person is said to play the roleof passenger in its association with the Elevator class.

12:Begin the definition of a method called LoadPassenger. Declareit public to be part of the interface of the Elevator class.

14:Instantiate (create) a new object of class Person by using thekeyword new. Assign this object to the passenger variable.

17:Begin the definition of a method called InitiateNewFloorRequest. Declareit public to be part of the interface of the Elevator class.

19:Call the NewFloorRequest method of the passenger object; assign thenumber returned by this method to the requestedFloor variable.

122 C# PRIMER PLUS

LISTING 5.2 continued

20-21: Print information about the “movement” of the operatoron the command console.

22-23: Calculate the number of floors traveled by the elevator on oneparticular trip (line 23). Add this result to the total numberof floors already traveled by the elevator.

24:Let the Elevator “travel” to the requested floor by assigning thevalue of requestedFloor to currentFloor.

29:Whenever the ReportStatistics method is called, print out thetotalFloorsTraveled variable.

33: Begin the definition of a class named Person.

35:Declare randomNumberGenerator to be a variable, which can hold anobject of class System.Random.

37:Begin the definition of a special method called a constructor, which willbe invoked automatically whenever a new object of class

Person is created.

39:Create a new object of class System.Random by using theC# keyword: new; assign this object to therandomNumberGenerator variable.

42:Begin the definition of a method called NewFloorRequest. public declaresit to be part of the interface of the Person class. int specifies

it to return a value of type int.

43:The Person decides on which floor “he” or “she” wishes to travel toby returning a randomly created number between 1 and 30.

51:The Building class declares an instance variable of type Elevatorcalled elevatorA. The Building class is said to have a “has-a”(or a composition) relationship with the Elevator class.

53: Begin the definition of the Main method where the program will commence.

55:Instantiate an object of class Elevator with the keyword new; assignthis object to the elevatorA variable.

56:Invoke the LoadPassenger method of the elevatorA object.

57-61: Invoke the InitiateNewFloorRequest method of theelevatorA object 5 times.

62: Invoke the ReportStatistic method of the elevatorA object.