Last modified: Feb 16, 2014
Classification: Where do Classes Come From?
A key step in any OO analysis or design is identifying the appropriate classes.
incremental
We tend to add a few classes at a time.
iterative
We may revisit earlier decisions and change them.
We often identify classes and then later add details about their relationships to other classes.
Grouping Objects into Classes
We may identify groups of objects as a class because they have common
properties,
e.g., we regard all things that have titles, authors, and textual content as documents, regardless of whether they are in a print medium, a file, or even chiseled into a set of stone tablets.
Don’t make the mistake of grouping things into a class because they have common property values.
A “collection of documents” can be a class. The values of that class can be collections that were selected by many different criteria.
By contrast, the collection of documents written by Mark Twain (i.e., whose author property has the value MarkTwain) is not a class. It’s just a particular value of the “collection of documents” class.
behaviors,
e.g., the set of all documents that can be loaded from and saved to a disk might represent a distinct class ElectronicDocuments.
Where do we get the information from which we can identify classes during analysis?
The “program as simulation” philosophy suggests that we should be looking for a model of the “real world”.
Initially we will build that model by looking at informal English descriptions of the world.
Later, from use cases (scenarios)
Working from Informal Descriptions
Generally, this is done at the start of construction of a domain model or, if no domain model is needed, of the analysis model.
A fairly simple way to get started is to scan the informal statement looking for noun phrases and verb phrases
Nouns represent candidate objects
Verbs the messages/operations upon them (responsibilities)
This doesn’t scale well to large projects/documents, but it is simple and often a useful starting point.
After that, we move on by exploiting our knowledge to assign the responsibilities to the appropriate and to classes, refine our choice of classes and responsibilities.
Use-Case analysis
A use-case is a particular pattern of usage, a scenario that begins with some user of the system initiating a transaction or sequence of related events.
We analyze use-cases to discover the
objects that participate in the scenario
responsibilities of each object
collaborations with other objects
More on this in later lessons.
CRC Cards
Early in our development process, we won’t want to be slowed down by the need to construct detailed documentation that looks “pretty” enough to show people outside our team (management or domain experts).
CRC cards are a popular way of capturing early classification steps.
CRC
CRC (Class, Responsibility, & Collaborators) cards are a useful tool during early analysis, especially during team discussions.
They are not exactly a high-tech tool:
4x6 index cards
used to take notes during analysis,
CRC Cards are Informal Documentation
The point of CRC cards is to capture info about an analysis discussion without slowing down that discussion so someone can take nicely formatted notes.
They aren’t pretty.
They aren’t something you ever want to show your customers or even your own upper-management.
If you come out of a group meeting and your CRC cards aren’t smudged, dog-eared, with lots of scratched-out bits, you probably weren’t really trying.
CRC Card Layout
labeled with class name
divided into two columns
responsibilities
A high-level description of a purpose of the class
collaborators
other classes with which this class must work with (send messages to) to fulfill this class’s responsibilities
ClassName | |
---|---|
responsibility 1 | collaborator 1 |
responsibility 2 | collaborator 2 |
responsibility 3 | |
CRC Card Example
Librarian | |
---|---|
Handles checkout and checkin of publications | Patrons |
Reshelves books | Publications |
Manages new acquisitions of publications | Inventory |
Has name, ID#, branch assignment | Catalog |
The responsibilities will eventually evolve into messages that can be sent to this class and then into member functions of an ADT.
Being aware of that intention can be a good indicator of which class should receive a particular responsibility.
Assigning Responsibilities Example
For example, if I were told “a library patron will give a librarian a book to be checked out”, I would model this as
Librarian | |
---|---|
Handles checkout of books for patrons | |
… | |
Patron | |
---|---|
Librarian | |
but not as
Librarian | |
---|---|
Patron | |
---|---|
Asks librarian to check out book | Librarian |
When A does B to C
A useful rule of thumb is that if “A does B to C”, then
“doing B” is a responsibility.
But it is usually a responsibility of class C, not of A.
C is then a collaborator of A
In pseudo-code terms, we might say
void A::fulfillSomeOtherResponsibilityOfA(C c1)
{
⋮
c1.B();
⋮
}
Containers
A variation on this rule of thumb occurs when managing collections.
If I told you that “the librarian adds the book’s metadata%ifdef _printable [1] %endif to the catalog”, I would expect you to model that as
Catalog | |
---|---|
Permits addition of metadata | |
and not as
Metadata | |
---|---|
Can be added to a catalog | |
Containers (cont.)
Again, by analogy with programming, we understand that if you had something like
vector<int> v;
set<int> myList;
⋮
v.push_back(23);
myList.insert (23);
You would never say:
23.insertInto (myList);
Attributes
A common variation (used in the textbook) is to use the backs of the cards to list attributes.
We won’t do that. We’ll list known attributes among the responsibilities,
Librarian | |
---|---|
Handles checkout and checkin of publications | Patrons |
Reshelves books | Publications |
Manages new acquisitions of publications | Inventory |
Has name, ID#, branch assignment | Catalog |
Attribute Conventions
Singular and plurals are used in noun phrases to distinguish between single occurrences (“name”) and collections (“publications”).
Empty Columns
It’s OK for one or the other column to wind up being empty.
These often correspond to external systems or people who are acting spontaneously to initiate some action.
An empty list of collaborators can indicate that a class is a server - it accepts messages but sends out none. This is most likely in a “lower-level” class that is little more than a collection of attributes. Most systems have many such classes.
If both columns remain empty, however, that’s a good sign that the class may not be needed in your model.
Be careful, though, about jumping to this conclusion too soon. Dropping classes form the mode should only be done when you are nearing the completion of the model.
Common Mistakes in CRC Cards
Premature design: You aren’t doing code, selecting data structures, etc., yet. If you were doing those, you shouldn’t be using CRC cards.
Overly specific collaborators: There is no significance between the vertical match up of the responsibilities and the collaborators, There’s no implication that a particular collaborator goes with a responsibility “on the same line”.
Consequently, there’s no reason to list a collaborator twice.
Mis-assigned responsibilities: already discussed
Inconsistent collaboration: If you place a class B in the collaborator list of card A, then there needs to be some responsibility of B that it actually makes sense for A to call upon or make use of.
In particular, if class B has an empty responsibilities column, it really can’t appear as a collaborator of anything at all!
metafootn ↩