|
Table of Contents
Learning C++:
An Index of Entry Points
2. The A reference document on the basic elements of C++.
3. The Patterns
CRC cards are not just a gimmick. Check out The CRC Card Book by David Bellin and Susan Suchman Simone. It is in the NMHU library with call number: QA76.64 .B437 1997
A model of the White House drops off details, hopefully unimportant details. To model objects in the world using classes, you must determine the important properties and behaviors and ignore the rest.
Classes represent descriptions of some type of object. With CRC cards we attempt to find the properties and behaviors we want to describe using variable declarations (for the properties) and functions (for the behaviors).
Some professionals argue that large software engineering projects are the most complex tasks humans have to manage.
Most students hate teamwork - even when they are told that this is the way large programming projects are handled. Hate them or not, teamwork allows humans to deal with the complexity of the software engineering process.
We all like to ignore certain verbs - those that are used to tell us to do something we don't want to do!
Careful! The word "get" as used here has nothing to do with "getting information from a user". Indeed, note that we call the member functions that implement "get" using the word "Provide" - to indicate that an instance will provide the value of some property - not get it from a user.
CRC cards is not the only tool used by software engineers. Another popular approach involves Use Cases.
Check out this example using both CRC cards and Use Cases. |
A. The Idea of CRC Cards
In the CRC approach a design team gathers together with a stack of
index cards. Using the underlined nouns in the problem narrative, the team
comes up with the objects/classes required in the program. Someone writes
down a name for each class in the upper left corner of a card - one card
for each class. A line is then drawn down the middle of the card and on
the left we begin to list the responsibilities of objects belonging to
this class.
There are two kinds of responsibilities. First, an object is
responsible for knowing or being able to determine certain things about
itself. Some of the underlined nouns in the narrative represent such
responsibilities. In the example above instances of the class 'Person'
would be responsible for knowing their name and address. In many cases
these knowledge responsibilities will become properties of the
class but we will see exceptions to this.
The second type of responsibility involves the behaviors instances of
the class will expected to perform. Such behavioral responsibilities can
be as simple as reporting the value of some property or can involve
complex calculations and manipulations of data. The circled verbs in the
narrative act as clues in the discovery of these responsibilities.
On the right side of the CRC card we list other classes that this class
must use in order to carry out its responsibilities. Such required classes
are called collaborators. Thus we see where the name CRC comes from -
Classes, Responsibilities, Collaborators.
Notice the words 'responsibilities and 'collaborators'. These have been
chosen on purpose to emphasize that each object (instance of some class)
is to be considered as an 'actor'. Objects manage their internal state and
perform actions. They receive and respond to messages or
requests sent to them by other objects or 'main' and its related
non-member functions. This may seem a bit strange at first - as if we are
anthropomorphizing our programs. For the fun and ease of it, you might
want to imagine a program as some kind magical land where inanimate
objects come to life.
Consider as an example, a race car game played on a computer. An
object-oriented program for such a game would probably consist of a race
track class with one or more object instances representing possible race
tracks and a race car class with one or more instances representing the
various cars involved in a race. We humans do actually use phrases like
the 'response' of the car, and we can think of an instance of the class
'car' in this program as 'responding' to messages to accelerate or brake
or turn. In other words, each instance of the class 'car' must be
responsible for knowing its position, speed, and direction and for
accelerating, braking, and turning itself. The responsibilities of an
instance of race track might include displaying the race on the screen,
keeping track of (knowing) such things as who is in the lead and the
elapsed time of the race, and of informing a car when it has crashed into
a wall of the track.
This last may also seem strange but again, remember the magic land we
are in. Perhaps one should actually have a class 'wall', where some set of
instances of wall form part of an instance of track, and instances of wall
inform instances of car when a car has crashed into a wall. Walls would be
collaborators of track because a track would not know if there was a crash
(something it needs to find out about if it is to accurately display the
race) unless it gets the information from the walls of a track. (If this
seems a bit complex and far-fetched, don't worry much about it yet. The
details will come later.)
Back to our CRC cards, note that this approach does not directly
determine the properties of a class. However, some of the knowledge
responsibilities of a class will be implemented as properties and some
collaborators (such as walls in relation to tracks) will also become data
members (for example, tracks have walls as properties). Other properties
may become clear as we consider which underlined words in the problem
narrative are useful to the behaviors/responsibilities of the class.
B. Introducing Olympia and the CRC Process
Weekly Charge = Days per Week * ($0.05 per square feet + $5 per
desk)
Of course, contract information can change so the program should
be able to modify the contracts.
This problem description has been kept vague on purpose. Users rarely
can describe their own problems in a way useful to the programmer. It is
our job to tease out the information we need and hand it back to the user
to make sure our analysis is correct. As a first step then, here is a
problem narrative for this problem
Weekly Charge = Days per Week * ($0.05 per square feet + $5 per
desk)
This description is the same but more detailed than the original.
Hopefully, enough detail has been provided to help us discover the classes
involved as well as their properties, behaviors, and relationships. This
is a simple problem so it is likely that we will succeed. Be aware that a
more complex problem will require both a more detailed problem narrative
and a more complex analysis of that narrative.
C. What the Underlined Nouns Tell Us Weekly Charge = Days per Week * ($0.05 per square feet + $5 per
desk)
In this example all nouns and verbs have been underlined or italicized
the first time they appear. Since the underlined and italicized words are
to be used as clues in discovering the necessary classes etc., it is not
necessary to 'mark' clues that have already been discovered. Likewise,
words that really refer to the same thing, as in "office complex" and
"office" are not both 'marked'.
Many of the words here really are irrelevant to the process and can be
weeded out immediately. Our goal is to create a 'model' of the contract
world of Olympia. Since concepts such as 'program' and 'user' (of the
program) are not part of that world, they are not part of the model and
can be ignored.
Perhaps not as obvious, 'Olympia' and 'business' can also be ignored.
The task here is to discover those objects that are part of Olympia's
business world. Olympia herself owns that world. She is not contained in
that world. Likewise, the business world is what is being modeled - it is
not part of itself. Any words in a problem narrative that name the world
being modeled or the 'owner' of that world can be ignored. It is not that
these words could be left out of the problem narrative. They are necessary
to describe the problem but they are not useful as clues in finding the
classes and class responsibilities.
The nouns that are left include:
Now we need to determine which of these represent classes, which
represent objects, which represent properties of objects, which represent
other elements of the program, and which can be ignored. Let's start with
contract. It certainly is a thing, an object and it doesn't sound like a
property or a description of some other object. Contracts seem to 'exist'
by themselves in the little world we are modeling. As a matter of fact,
there are five of them which means that there are five instances of
contract. This is a sign that we might have a class. Further, each
individual contract is unique but it is likely that they all have
characteristics in common - another sign that we have a likely candidate
for a class. Let's consider it a class for the moment.
How about 'square footage'. By the way it is written, it is clear that
it is meant to describe a characteristic of a contract - contracts have a
square footage associated with them. Therefore 'square footage' is a
knowledge responsibility and probably a property of the contract class.
This gives us more confidence that 'contract' is a likely class - we have
found a responsibility for it. Classes without responsibilities are of
little use in a program.
Next comes 'number of desks'. Here, perhaps, we cheated in our initial
underlining. 'Number of desks' is most likely a property of contract just
as 'square footage' was. If we had just underlined the word desk, we would
have had to have been a bit more careful. Desks certainly are objects and
therefore the concept of desk certainly could represent a class in our
program. However, in this program do we care about desks in any other way
other than the number of them. For example, do we care about any of the
possible characteristics of desks? None of the rest of the underlined
nouns refer to desks so the answer seems to be no. When we get to the
italicized verbs we will also see that none of them describe behaviors of
desks so nothing about desks seems to concern us or Olympia except their
number in a contract. Therefore in this program desks are not objects.
Note that in other programs desks could play a significant role and
could need to be modeled as objects. Consider a program which acts as a
tool for doing office designs. In such a program users would be creating
office spaces and placing desks as well as chairs, tables, portable walls,
etc. in those spaces as part of the design process. Such a program would
need to keep track of the location of each desk, its style, size etc.
Desks could be moved around, deleted, and otherwise modified. Now desks
have properties (characteristics) and behaviors, making them very likely
candidates for class status.
Back to our problem: 'number of days' fits in the same category as
'square footage' and 'number of desks'. Knowing or being able to determine
the 'Per week charge' is also a knowledge responsibility of the contract
although we will see later that there is some discussion about how to
represent it. That leaves four nouns to analyze. 'Information' is really
just a collective word for the various properties we have been discussing.
It was useful in the problem narrative but adds no detail here so can be
ignored. ' Formula' is tricky. Yes, one can say that contracts have a
formula but we will see that the formula here will be represented as a
piece of code that calculates the 'per week charge'. In a programming
context the word formula hints at an action ( a piece of code) more often
than at a property.
The word 'week' also requires a bit of analysis. The problem narrative
needs to include information about the time frame of a contract, but does
the idea of time have a place in the program? A week is certainly a thing,
but there is nothing the program does with 'weeks' so it is unlikely to
become a class. Could it be a property? Since 'contract' is our only
class, 'week' would have to be a property of 'class'. By itself, however,
week is not a descriptive term like "hair color" or "number of days". It,
therefore, does not seem to make a good property.
The problem narrative includes the phrase "per week" and we could
imagine a property that referred to the length of time of a contract, as
in "by the week" or "by the day" or "by the month". In this sense, the
charge for a contract or the billing period might depend on this length of
time. Note, however, that, under this interpretation, 'week' is not the
name for a property but a possible value of a "time period" property. All
this is unimportant in the context of this specific problem because all
contracts are described in terms of a week and a property with only one
possible value isn't worth noting.
Finally, we have 'office complex'. There are a number of office
complexes involved in this program - one for each contract probably. Yet,
as with desks, there do not seem to be any properties (or behaviors as we
will see in a moment) associated with this potential class. If you think
about it, we really aren't interested in office complexes in this program
except that contracts are associated with them. Thus, this noun seems to
be another one that was useful in the problem narrative but not useful in
the program itself.
We wind up with one class (Contract) and a small set of knowledge
responsibilities for that class. At this point you may be thinking, "You
(the authors) wound up with that, but not me. I could never repeat this
process on my own." You may well be correct. Indeed, it would be possible
and quite easy to come up with a different and probably invalid set of
candidate classes. The class discovery process is an art form and there is
no clear set of criteria for determining when one has come up with the
best set of classes. Object-oriented analysis and design is not easy.
There is no simple algorithm for it. (If so, we could probably turn the
process over to a computer and forget about it.) The "underline the noun
and circle the verb" approach used here is only to get you started. You
will need to use all your common sense and analytic skills to arrive at a
complete analysis.
That is where the team approach comes in. A team is more likely to
discover all the necessary classes, their responsibilities, and their
collaborators. Object-oriented analysis and design is so hard that, in
practice, even experts often work in teams. In fact the CRC approach is
specifically meant to be executed in teams. Well managed teams allow the
best ideas of each individual to come through while filtering out the
mistakes. Students often resist working in teams for any number of reasons
(grades, schedules....) but if you want to be trained for the real world,
you need to get used to team work.
Part of the team approach used with CRC cards includes role playing.
Team members decide on a few basic classes and then role play various
scenarios a program would be expected to handle. The goal is to discover
if these indeed are the correct classes, what other classes might be
required, what are the responsibilities of the required classes, and how
the classes collaborate.
What you also need to do at this point is carefully study the designs
and resulting programs of others who are more experienced. Then, practice
on your own or in groups. That is what much of learning to program is
about.
D. What the Verbs Tell Us
We have already discovered at least some of the knowledge
responsibilities: Know the square footage Know the number of desks Know
the number of days Know the per week charge.
Now we proceed to determine the behavioral responsibilities. To
accomplish this we work with the italicized verbs. As with the nouns, we
first need to consider if there are any verbs that can be easily ignored.
Remember that we are looking for behaviors that instances of the class
should be expected to perform. Therefore, what we are looking for here are
behaviors that contracts will be expected to perform. (Again, it might
help if you think of a contract as an actor.)
Problem narratives often include verbs that refer to the person or
organization for whom the program is being written. In this example, we
have "Olympia owns" , "Olympia wishes", and "she
has". These are not actions of a contract and can be ignored. The
remaining verbs include:
It turns out that many verbs provide very strong
hints about the knowledge and behavioral responsibilities of classes. For
example, whenever you see verbs such as "keep track of", "saves",
"stores", or "holds", whose subject noun is a candidate class (such as
Contract in this example), the words after those verbs are likely to be
knowledge responsibilities of the class. In the program narrative the
first use of 'keeps track of' refers to the program itself and can be
ignored on the same basis that 'owns', wishes' and 'has' were ignored.
However, the second usage has 'contract' as its subject and refers to
'square footage', number of desks' and 'number of days'. We can interpret
this to mean that instances of class 'contract' have the responsibility of
keeping track of their 'square footage', number of desks' and 'number of
days'. Here is corroborative evidence that we are on the right track with
our analysis.
Such verbs hint at the characteristics (what we are calling the
properties) of a class, but they do not indicate any behavior required of
the class. On the other hand, verbs such as change, update, set, or modify
indicate both possible properties and the action of changing, updating,
setting or modifying the values of those properties. (They indicate
properties because something can't be changed or modified or set unless it
exists and it is not the object that changes - objects of one type (class)
do not become objects of another type). Therefore, in our example, we can
conclude that instances of class contract must be able capable of
(responsible for) changing the 'information' they hold concerning the
'square footage', number of desks' and 'number of days' of the instance.
At this point we have the following responsibilities for the 'contract'
class:
Behavioral Responsibilities:
Another verb that often provides a useful hint is 'get'. When used in a
form such as "the user should be able to get….", this word strongly
implies that the class must be capable of reporting the values of the
properties it is responsible for knowing. This does not mean that the
values are output but rather that they can be retrieved from an instance
and used by some other part of the program. In concrete terms what this
means is that for each property there is a function (after all, functions
implement behaviors) that returns the value of the property. It is usually
considered wise to not have the function output the value itself because
the object does not know how the value is to be used. Maybe it is not
going to be output at all. Or, maybe it is to be used in a calculation or
in a test condition.
In our example then we need at least three such 'get' functions, one
for 'square footage', number of desks' and 'number of days'. In this
material we will use the word 'provide' instead of 'get' to avoid some
confusions students sometimes have. Thus, the contract class has the
following additional behavioral responsibilities:
The idea is that an instance of the
class 'Contract' will, upon request, provide the value of the desired
property. We probably also need a 'get' or 'provide' function for the "per
week charge" but this is a special kind of knowledge responsibility since
it is a calculated value. In other words, the Contract class has the
responsibility of knowing the "per week charge" more in the sense of
knowing how to calculate it than in immediately knowing its value.
When we look at the verb 'calculate', the question arises: should there
be a memory location set aside to hold the 'per week charge' or should it
be calculated every time it is needed? If it is calculated every time it
is requested then the program must do the math over and over even if none
of the values upon which it depends have changed. Why do that work over
and over? But, suppose we do set aside a memory location to hold the 'per
week charge' and do the calculation once. Now, suppose that later the
number of desks in the office changes. Since this is one of the properties
upon which the 'per week charge' depends, any change in it forces a change
in the per week charge. How do we make sure that the 'per week charge' is
again calculated? It turns out that although one can write code to
accomplish this, it is often easier to simply have an instance redo the
calculation whenever the value is asked for. For us then, the conclusion
will be that the contract class will have a 'Provide Per Week Charge'
function, but there will not be a 'weekly charge' property. Each time it
is called, the 'Provide Per Week Charge' function will perform the
calculation and immediately return the result.
The reader should pay careful attention to what is happening here. The
"per week charge" knowledge responsibility is being handled via a
calculation BUT users of the class (users here means programmers who
include the class in their code) will have no idea how the "per week
charge" is generated. Outside the Contract class there is no visible
difference between 'ProvideSquareFootage' and 'ProvidePerWeekCharge'.
Indeed, if later we decided that the internal structure of the 'Contract'
class should change to explicitly include a "per week charge" property,
any program using this class would not need to change. This is one of the
more powerful advantages of encapsulation.
Note also that the discussion here has slipped a bit into issues of
'how' not just 'what' the Contract class will do. Analysts and Designers
should do all they can to keep these separate but it is not always
possible to do so. That is part of the complexity of the real world and
real world programming.
There are two verbs left:
Neither of them really involve behaviors of contracts. The verb 'to be
cleaned' certainly is not a behavior of a contract, while 'involves'
implies a relationship - perhaps between instances of Contract and
instances of some other class.
Is it possible that we have skipped a class or classes - classes that
would be responsible for 'cleaning' or that would be 'involved' with the
contract class? This possibility should not be overlooked - one part of
the design process can often help in some other aspect of design. However,
in this case there is nothing to worry about. First, the problem narrative
says that "contracts involve office complexes" but we have already
carefully analyzed the noun office complex and decided that it did not
represent a class that would be useful in this program. Second, the other
verb really refers to the user of the program - the user or an associate
who would be doing the 'cleaning'. In our earlier analysis we decided that
'user' was not a useful class concept in our program.
To summarize: Our analysis shows that we need one class, call it
Contract, which has four knowledge responsibilities and seven behavioral
responsibilities:
Behavioral Responsibilities:
Three of the four knowledge resupplies will become properties - square
footage, number of desks, and number of days.
Since there is only one class, we do not need to worry about
collaborators. Here then is the CRC card for the class 'Contract'
![]()
E. Some Additional Ideas on Discovering the Responsibilities of a
Class
These functions are often referred to as interface functions
because they allow a program's code to access (interface with) the
encapsulated parts of an instance. That part of a program's code that does
not belong to a class does not have direct access to the encapsulated
properties of the class. However, through the interface functions, the
code can retrieve and change the property values of an instance.
Such interface functions are often not 'discovered' until one actually
begins coding. That is perfectly OK - a good design is meant to give the
programmer a plan to follow and plans can be modified along the way.
However, it is best to determine as much as you can at design time so you
should ask the following questions of each class:
|