Академический Документы
Профессиональный Документы
Культура Документы
Handout Overview
This handout describes the object-oriented design process, and the way in which it
differs from the conventional design process. The four phases of the object-oriented
design process are described and then illustrated with a case study.
1. Object-Oriented Design
The object-oriented design process can be divided into four main stages:
• Identify the objects
• Determine the relationships between the objects
• Determine the attribute/behaviours of the objects
• Design the driver
In order to identify what objects your program should have you will need to
review the problem specification. Remember that classes represent things: a
student is a thing, as is a foreign student, etc. Try to work out what things
your program will need to deal with and note them down as potential classes.
2
Next analyse the relationships between these potential classes: for example a
foreign student and a student are clearly related. But what type of
relationship is it? In Handout 1 three types of relationship were introduced:
is-a relationships, has-a relationships and uses-a relationships.
Remember that you should use is-a relationships when one object is a type
of another object. You should use has-a relationships when one object
contains another object. Uses-a relationships are less easy to define and less
common. As an example, suppose we have a Clock class that has a public
member function currentTime() that returns the current system time. If
another object in the program wanted to know the system time it would need
to use the Clock class, so it would send a message to a Clock object asking it
to execute the currentTime() function. The Clock object would then
send a message back indicating the current time. Uses-a relationships are
generally implemented by classes sending messages to each other, as in this
example.
Once you have identified potential classes and the relationships between
them, this should help you to sketch out an inheritance hierarchy for your
program.
Once we have decided how the objects will interact, we need to think about
what responsibilities object will have. For example, if the interaction
between object A and object B involves object A sending a message
requesting a particular operation from object B, then it is the responsibility
of object B to perform that operation. The responsibilities of an object can
3
involve both behaviours (i.e. operations) and attributes (i.e. storing data).
These equate to data members and member functions in C++.
Finally, now that we have defined the objects, their public interfaces and
their behaviours and attributes, we need to design the driver. You can think
of the driver as being the glue that binds the objects together, or the main
algorithm of the program that makes use of the objects. In C++ the driver
corresponds to the main function.
Once you have completed and reviewed these four steps, you can produce a
prototype implementation. Often in producing this prototype you may realise
that you need to go back to the first two steps and modify your class
hierarchy. Program design is always an iterative process: you will go through
a number of cycles, or iterations, before you reach a design and
implementation you are happy with.
Like traditional program design you only really become skilled and
confident at object-oriented design by practice, so do not worry too much if
it does not come naturally at first. Practice makes perfect …
4
The first stage in the design of our program is to identify the objects that our
application will consist of. Looking through the program requirements and
choosing the nouns is usually a good start. Doing this with our requirements gives
us the following potential objects:
company vehicle computer software
wheeled vehicle boat car
bicycle people top speed
model name cost wheel
fuel tank capacity fuel efficiency gears
mountain bike racing bike rowing boat
5
Next we must determine what interactions and relationships there are between our
potential objects. A glance through the remaining candidates reveals a number of
obvious is-a relationships,
a wheeled vehicle is-a vehicle;
a boat is-a vehicle;
a car is-a wheeled vehicle;
a bicycle is-a wheeled vehicle;
a mountain bike is-a bicycle;
a racing bike is-a bicycle;
a rowing boat is-a boat;
a speedboat is-a boat;
a dinghy is-a boat;
a yacht is-a boat;
and also a number of has-a relationships,
a vehicle has-a top speed;
a vehicle has-a model name;
a vehicle has-a cost;
a wheeled vehicle has-a wheel;
a car has-a fuel tank capacity;
a car has-a fuel efficiency;
a bicycle has-a gears.
Bearing all this in mind, we can sketch out an initial inheritance hierarchy for our
program. Figure 1 shows such a hierarchy. The is-a relationship between boats
6
and vehicles means that the boat class inherits, or derives, from the vehicle class.
Similarly wheeled vehicle derives from vehicle, and both car and bicycle derive
from wheeled vehicle. Notice that we have now selected five of the candidates to
be objects in our solution domain. Many of the remaining candidates will
reappear when we start to add data members and member functions to these
objects in the next phase.
Now we must decide what information each of the 5 objects needs to store, and
what operations they need to perform. To determine this, we can use the
remaining nouns from our list of candidates, and refer to the initial program
requirements. For example, for the top speed the requirements state that this value
must be stored for every vehicle, so this item should be added as a data member in
the vehicle class. All classes that derive from vehicle, whether directly or
indirectly, will then inherit this data member. The mountain bike and racing bike
items are really just alternative values for a category data member, which should
be stored in the bicycle class. The requirements also specify that for every vehicle
we should be able to calculate the registration cost. Therefore we should add a
member function to the vehicle class. However, the requirements also state that
the nature of this calculation will be different for cars, bicycles and boats, so in
this case the function should be a virtual function. (Remember from Handout 2
that virtual functions define type-dependent operations in an inheritance
hierarchy.) In addition, we do not want the vehicle class to provide an
implementation of this function (only car, bicycle and boat should provide
implementations) so it should be a pure virtual function. We can now expand our
inheritance hierarchy to include attributes (i.e. data members) and behaviours
(member functions).
7
The final stage of the design process is to design the driver of the program. For
C++ programs, this means deciding what the main function will do, and how it
will use the classes that we have defined. In our case, the program requirements
do not state what the database should be used for, so this stage is not important.
We could, if we wanted to, design a user-interface that lets a user interact with out
database of vehicles. However, for the purposes of demonstration we will just
design a simple main function that creates a few objects and calls the member
functions.
The full code listing for the vehicle database case study is shown below. The
source code is split into 3 files: “Vehicle.h” contains the class definitions;
“Vehicle.cpp” contains the function bodies; and “VehicleTest.cpp” contains the
main function.
Notice that we have used information hiding to hide the implementation details of
the classes from the rest of the program. The data members are all defined as
protected, and public member functions are used to assign values to them.
These public member functions define the public interface of the class.
8
“Vehicle.h”
class Vehicle {
protected:
int people;
float speed;
char *model;
float cost;
public:
void SetPeople (int p) {people = p;}
void SetSpeed (float s) {speed = s;}
void SetModel (char *m) {model = m;}
void SetCost (float c) {cost = c;}
virtual float CalcRegistration() = 0;
};
“Vehicle.cpp”
#include "Vehicle.h"
float Car::CalcRegistration () {
return (10 * tank_capacity);
}
float Bicycle::CalcRegistration () {
return 55;
}
float Boat::CalcRegistration () {
float reg = 0;
switch (category) {
case rowing: reg = 100;
break;
case speedboat: reg = 1000;
break;
case dinghy: reg = 200;
break;
case yacht: reg = 10000;
break;
};
return reg;
}
“VehicleTest.cpp”
#include <iostream.h>
#include "Vehicle.h"
main () {
Car c; //test out the car class
c.SetPeople(4);
c.SetSpeed(95);
c.SetModel("Lada");
c.SetCost(20000);
c.SetWheels(4);
c.SetTankCapacity(100);
c.SetFuelEfficiency(10);
cout << "Registration cost for Lada = "
<< c.CalcRegistration() << endl;
Note: The full source code listings for the example in this handout can be found on the
FBE network server: to access them, open My Network Places, double-click on
MU-FBE, then FBE-SERVER and then browse to:
Courses\ICT122 – Object-Oriented Programming\src\Handout 5