Where do object and class diagrams come from? We now study a way to discover them.
When someone wants a machine built, they tell us how they want the machine to behave when they use it. They give us examples, and we develop the machine's structure and control from the examples.
An example behavior is called a use case. A use case is a "round of play" of a game, or a "session" with a tool, or a "transaction" with a reactive system. It is the input-output description of the system we must build. It describes external behavior.
Example: a use case of a candy-bar vending machine goes like this:
A use case describes external behavior, from the user's perspective. But there is also the internal behavior that occurs from the machine's perspective. When we include the latter into the use case, we have a use-case realization that tells us how the machine operates. It is the "high-level algorithm" of the system we must code. For the candy machine, the use-case realization might go like this:
Notice that the use-case realization uses nouns that name the internal components and active verbs that state the actions the components take. (Example: "The button's controller tells the database to subtract the price of the bar....")
When we write a use-case realization, we force ourselves to use nouns that name the internal components and use active verbs that state actions --- the nouns suggest the classes/objects we must build, and the verbs suggest the methods we must write!
With enough use cases documented and realized, we can build a machine that does all the desired behaviors. Use-case realizations help us design the class diagram and code the classes. (In the "old days", the use-case realizations were called "high-level algorithms" --- the outlines of the code we must write.)
Here is a use-case realization of one round of a simulated Blackjack card game, where a human plays against a "house player".
When writing the realization part, we should first think about which "entities" will be part of the realization. For a card game, this means Cards, a Deck, human and computerized card Players, and a Dealer. The use-case realization explains what the entities do:
for each Player p, both human and computerized: Dealer deals two cards from the Deck and gives them to p
if human's score == 21 or dealer's score == 21, determine the result of the round --- win, loss, tie (details supplied later); terminate round else continue :
for each Player p, first the human and then the computerized, Dealer asks: while p wants a card and p's hand's score <= 21 : Dealer deals a card from the Deck and gives it to p
for each Player p: p shows its hand to the Dealer so that the Dealer can calculate the hand's score and display the results. Dealer compares scores of all hands and announces the winner
Look at the above use-case realization.
Before we start coding classes, we should draw pictures of how the steps in our use-case realization are sequenced as method calls from one entity to the next. There are two standard diagram formats for drawing a use-case realization: communication diagrams and sequence diagrams.
A communication diagram (also called a "collaboration diagram") is an object diagram labelled by the method calls that occur during a use-case realization. We should always draw an object diagram when we are designing a system, so it is not much extra work to make the object diagram into a communication diagram.
Here is a simplified version of the previous use-case realization for a round of card play (we will assume that no player scored 21 at the start):
The labels on the arrows are method calls; for example, 1.0 dealCard states that as the opening action for (1) above, the Dealer object calls the Deck object's dealCard() method --- so, we must define method, dealCard, in class Deck, so that Dealer can call it. The numbering lets you follow the sequence of calls that realize the use case. The diagram lets see which methods should be coded in which classes.
In this way, a communication diagram almost maps out the code that we write.
You can always add more details to the communication diagram, say, add the arguments to the method calls and the answers that are returned (draw some back arcs), if this helps you better understand how to design the system.
Also, you can always state fewer details in the communication diagram,
for example, just list the methods that are called during all the steps of the use-case
realization:
This gives you lots of clues for drawing the class diagram.
Since there is more room to list the method calls, it is easy to label them with their arguments and returned answers, like this:
From a sequence diagram, you should be able to draw the communication diagram, and vice versa.
Communication and sequence diagrams are important documentation tools for a finished system. So, even if you do not find them so helpful for design and coding, you might draw them so that you can more easily explain your work to your colleagues.
The class diagram is drawn by extracting from the communication diagrams the names of the entities and making them into classes. The method-labels on the arcs are moved into the classes as methods. Next, list the fields (attributes) within the classes.
This step is not completely mechanical --- you might have two distinct entities that should be instances of the same class (e.g., the 52 cards in a card game will all be constructed from the same class Card), and you might want to insert an interface or a delegate where you see the need (e.g., to mark off a subassembly, or to isolate a component, or to make a connection point for an event-handler method). But the communication diagram gives you lots of useful hints for drafting the class diagram.
"Test" the object diagram by labelling its arrows with the actions that are used in the use-case realizations --- this is a communication diagram. (If you want more detail, draw the corresponding sequence diagrams.)
By the way, the techniques outlined in this Lecure Note are sometimes called (Booch-Rumbaugh) object-oriented design --- a computer system is designed from use-case realizations as a collection of objects that communicate via method calls.
If a software system is built solely from use-case realizations, such that
It takes a lot of experience to do well agile development (and frankly, C# isn't the best language for doing it), but if you have good skills at using interfaces and delegates, you can make it happen.