13. Overview of UML for C# Programmers

image

Angela Brooks

The Unified Modeling Language (UML) is a graphical notation for drawing diagrams of software concepts. One can use it for drawing diagrams of a problem domain, a proposed software design, or an already completed software implementation. Fowler describes these three levels as conceptual, specification, and implementation.1 This book deals with the last two.

Specification- and implementation-level diagrams have a strong connection to source code. Indeed, it is the intent for a specification-level diagram to be turned into source code. Likewise, it is the intent for an implementation-level diagram to describe existing source code. As such, diagrams at these levels must follow certain rules and semantics. Such diagrams have very little ambiguity and a great deal of formality.

On the other hand, diagrams at the conceptual level are not strongly related to source code. Rather, they are related to human language. They are a shorthand used to describe concepts and abstractions that exist in the human problem domain. Since they don’t follow strong semantic rules, their meaning can be ambiguous and subject to interpretation.

Consider, for example, the following sentence: A dog is an animal. We can create a conceptual UML diagram that represents this sentence, as shown in Figure 13-1.

Figure 13-1. Conceptual UML diagram

image

This diagram depicts two entities—Animal and Dog—connected by generalization relationship. An Animal is a generalization of a Dog. A Dog is a special case of an Animal. That’s all the diagram means. Nothing more can be inferred from it. We might be asserting that our pet dog, Sparky, is an animal; or, we might be asserting that dogs, as a biological species, belong to the animal kingdom. Thus, the diagram is subject to interpretation.

However, the same diagram at the specification or implementation level has a much more precise meaning:

public class Animal {}
public class Dog : Animal {}

This source code defines Animal and Dog as classes connected by an inheritance relationship. Whereas the conceptual model says nothing at all about computers, data processing, or programs, the specification model describes part of a program.

Unfortunately, the diagrams themselves don’t communicate what level they are drawn at. Failure to recognize the level of a diagram is the source of significant miscommunication between programmers and analysts. A conceptual-level diagram does not define source code; nor should it. A specification-level diagram that describes the solution to a problem does not have to look anything like the conceptual-level diagram that describes that problem.

All the rest of the diagrams in this book are at the specification/implementation levels and are accompanied by corresponding source code, where feasible. We have seen our last conceptual-level diagram.

Following is a very brief tour of the primary diagrams used in UML. Then, you will be able to read and write most of the UML diagrams you will usually need. What remains, and what subsequent chapters address, are the details and formalisms that you will need to become proficient in UML.

UML has three main kinds of diagrams. Static diagrams describe the unchanging logical structure of software elements by depicting classes, objects, and data structures and the relationships that exist among them. Dynamic diagrams show how software entities change during execution, depicting the flow of execution, or the way entities change state. Physical diagrams show the unchanging physical structure of software entities, depicting physical entities, such as source files, libraries, binary files, data files, and the like, and the relationships that exist among them.

Consider the code in Listing 13-1. This program implements a map based on a simple binary tree algorithm. Familiarize yourself with the code before you consider the diagrams that follow.


Listing 13-1. TreeMap.cs

using System;

namespace TreeMap
{
  public class TreeMap
  {
    private TreeMapNode topNode = null;

    public void Add(IComparable key, object value)
    {
      if (topNode == null)
        topNode = new TreeMapNode(key, value);
      else
        topNode.Add(key, value);
    }

    public object Get(IComparable key)
    {
      return topNode == null ? null : topNode.Find(key);
    }
  }

  internal class TreeMapNode
  {
    private static readonly int LESS = 0;
    private static readonly int GREATER = 1;
    private IComparable key;
    private object value;
    private TreeMapNode[] nodes = new TreeMapNode[2];

    public TreeMapNode(IComparable key, object value)
    {
      this.key = key;
      this.value = value;
    }

    public object Find(IComparable key)
    {
      if (key.CompareTo(this.key) == 0) return value;
      return FindSubNodeForKey(SelectSubNode(key), key);
    }

    private int SelectSubNode(IComparable key)
    {
      return (key.CompareTo(this.key) < 0) ? LESS : GREATER;
    }

    private object FindSubNodeForKey(int node, IComparable key)
    {
      return nodes[node] == null ? null : nodes[node].Find(key);
    }

    public void Add(IComparable key, object value)
    {
      if (key.CompareTo(this.key) == 0)
        this.value = value;
      else
        AddSubNode(SelectSubNode(key), key, value);
    }

    private void AddSubNode(int node, IComparable key,
      object value)
    {
      if (nodes[node] == null)
        nodes[node] = new TreeMapNode(key, value);
      else
        nodes[node].Add(key, value);
    }
  }
}


Class Diagrams

The class diagram in Figure 13-2 shows the major classes and relationships in the program. A TreeMap class has public methods named Add and Get and holds a reference to a TreeMapNode in a variable named topNode. Each TreeMapNode holds a reference to two other TreeMapNode instances in some kind of container named nodes. Each TreeMapNode instance holds references to two other instances in variables named key and value. The key variable holds a reference to some instance that implements the IComparable interface. The value variable simply holds a reference to some object.

Figure 13-2. Class diagram of TreeMap

image

We’ll go over the nuances of class diagrams in Chapter 19. For now, you need to know only a few things.

• Rectangles represent classes, and arrows represent relationships.

• In this diagram, all the relationships are associations. Associations are simple data relationships in which one object holds a reference to, and invokes methods on, the other.

• The name on an association maps to the name of the variable that holds the reference.

• A number next to an arrowhead typically shows the number of instances held by the relationship. If that number is greater than 1, some kind of container, usually an array, is implied.

• Class icons can have more than one compartment. The top compartment always holds the name of the class. The other compartments describe functions and variables.

• The «interface» notation means that IComparable is an interface.

• Most of the notations shown are optional.

Look carefully at this diagram and relate it to the code in Listing 13-1. Note how the association relationships correspond to instance variables. For example, the association from TreeMap to TreeMapNode is named topNode and corresponds to the topNode variable within TreeMap.

Object Diagrams

Figure 13-3 is an object diagram. It shows a set of objects and relationships at a particular moment in the execution of the system. You can view it as a snapshot of memory.

Figure 13-3. TreeMap object diagram

image

In this diagram, the rectangle icons represent objects. You can tell that they are objects because their names are underlined. The name after the colon is the name of the class that the object belongs to. Note that the lower compartment of each object shows the value of that object’s key variable.

The relationships between the objects are called links and are derived from the associations in Figure 13-2. Note that the links are named for the two array cells in the nodes array.

Sequence Diagrams

Figure 13-4 is a sequence diagram. It describes how the TreeMap.Add method is implemented.

Figure 13-4. TreeMap.add

image

The stick figure represents an unknown caller. This caller invokes the Add method on a TreeMap object. If the topNode variable is null, TreeMap responds by creating a new TreeMapNode and assigning it to topNode. Otherwise, the TreeMap sends the Add message to topNode.

The Boolean expressions inside brackets are called guards. They show which path is taken. The message arrow that terminates on the TreeMapNode icon represents construction. The little arrows with circles are called data tokens. In this case, they depict the construction arguments. The skinny rectangle below TreeMap is called an activation. It depicts how much time the add method executes.

Collaboration Diagrams

Figure 13-5 is a collaboration diagram depicting the case of TreeMap.Add in which topNode is not null. Collaboration diagrams contain the same information that sequence diagrams contain. However, whereas sequence diagrams make the order of the messages clear, collaboration diagrams make the relationships between the objects clear.

Figure 13-5. Collaboration diagram of one case of TreeMap.Add

image

The objects are connected by relationships called links. A link exists wherever one object can send a message to another. Traveling over those links are the messages themselves. They are depicted as the smaller arrows. The messages are labeled with the name of the message, its sequence number, and any guards that apply.

The dot structure of the sequence number shows the calling hierarchy. The TreeMap.Add function (message 1) invokes the TreeMapNode.Add function (message 1.1). Thus, message 1.1 is the first message sent by the function invoked by message 1.

State Diagrams

UML has a comprehensive notation for finite state machines. Figure 13-6 shows just the barest subset of that notation.

Figure 13-6. State machine of a subway turnstile

image

Figure 13-6 shows the state machine for a subway turnstile. There are two states: Locked and Unlocked. Two events may be sent to the machine. The coin event means that the user has dropped a coin into the turnstile. The pass event means that the user has passed through the turnstile.

The arrows are called transitions. They are labeled with the event that triggers the transition and the action that the transition performs. When a transition is triggered, it causes the state of the system to change.

We can translate Figure 13-6 to English as follows:

• If we are in the Locked state and get a coin event, we transition to the Unlocked state and invoke the Unlock function.

• If we are in the Unlocked state and get a pass event, we transition to the Locked state and invoke the Lock function.

• If we are in the Unlocked state and get a coin event, we stay in the Unlocked state and call the Thankyou function.

• If we are in the Locked state and get a pass event, we stay in the Locked state and call the Alarm function.

State diagrams are extremely useful for figuring out the way a system behaves. They give us the opportunity to explore what the system should do in unexpected cases, such as when a user deposits a coin and then deposits another coin for no good reason.

Conclusion

The diagrams shown in this chapter are enough for most purposes. Most programmers could live without any more knowledge of UML than what is shown here.

Bibliography

[Fowler1999] Martin Fowler with Kendall Scott, UML Distilled: A Brief Guide to the Standard Object Modeling Language, 2d ed., Addison-Wesley, 1999.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
44.223.37.137