Again, building on the work we did in the last step, we go through the same cycle again, this time focusing down to the level of the class. The following sections describe the process in detail.
Look at each operation of your class, and determine its proper return value and parameters. Look at how the operation is used in earlier diagrams, and determine what information is provided to it and what is expected from it. Also consider whether any of its parameters should have default values.
You can add more detail to an operation in a Class Diagram by listing its parameters and return value. The parameters are listed inside the parentheses in a comma-separated list of the form param : type = default value, . . . . If a parameter has no default value, none is listed. Also, if there are any language-specific characteristics (such as .NET attributes that identify a parameter as in, out, or inout), these are listed in front of each parameter. The return type is listed after the parentheses, separated by a colon.
Take each class operation, and create a thorough class Activity Diagram for the use operation. (If you’re working through this process as an exercise, then you should do at least two class Activity Diagrams for practice, and more if you wish.) Define your Primary Scenario for each Activity Diagram, and then define your Exception Scenarios. As before, if you used subactivity states in the previous step to simplify your component Activity Diagrams, you may have given yourself a head start in designing your class Activity Diagrams.
Add swimlanes to each class Activity Diagram. Within a class Activity Diagram, the swimlanes will represent the class itself, along with its attributes, associations, and dependencies; so as you add swimlanes, you may discover that you need new attributes, associations, and dependencies. As you add swimlanes for these, update the class icons on related Class Diagrams. Swimlanes may also represent parameters to the method and return values, if these are required to carry out activities in the diagram. Once you’ve done this, then look for implementation operations required by the original Activity Diagram, and look for object flow states that may help explain how activities collaborate.
Now revise your class definition to depict the new attributes, associations, and dependencies required by the class Activity Diagrams. Examine each swimlane (other than the swimlane for the class).
If a swimlane should be an association and the class doesn’t have that association yet, add it. Then, based on how the attribute is used, select an appropriate type for it, and perhaps a default value if one is appropriate. Update the class to reflect these decisions. The attribute type is listed after the attribute name, separated by a colon. If there is a default value, it is listed after the type, separated by an equals sign.
For each class, consider drawing a separate Class Diagram centered on the class, with associated and dependent and realized classes and interfaces arrayed around it. Sometimes this “halo” diagram, depicting a class and everything related to it, can be a useful overview for understanding the class. (Other times, it can be too trivial to be useful.)
Let’s see how this process works in practice.
For our example, let’s look at the COwnerSet class. The Find Owner operation of the COwnerSet class needs the names of the owner to be found; and for simplicity, these names will be of type string. Create Owner needs the same information; and both operations may return a COwnerRecord. So COwnerSet looks like the class depicted in Figure 2-58.
Figure 2-58. Class Diagram for COwnerSet
Next, we need to create the Activity Diagrams for these two operations, but here, we’ll just focus on Find Owner. Figure 2-59 is an Activity Diagram for the Find Owner operation.
At this time, we can delve even further into implementation exceptions to aid us in preplanning how to detect and handle exceptions. In the same way that I used subactivity states to demonstrate common cancel handling (Figure 2-43), we could use subactivity states to depict common exception handling such as C#’s try/catch mechanism.
For example, in the diagram in Figure 2-59, there are two very likely exception categories. First, any time you call out to another component, exceptions are possible; and in particular, SQL operations are known to propagate exceptions. So we need to handle a range of possible SQL exceptions, which we can do by treating all possible SQL errors as a simple Null return. The second category of error is that we might not have enough memory to create an Owner Record. So, as shown in Figure 2-60, we’ll add exception handlers for these exceptions.
We might decide that this exception handling is too much detail for the design, and better left to code. Different teams will take different approaches to this technique.
Adding swimlanes and related activities to Figure 2-59, we get the Activity Diagram shown in Figure 2-61.
blog comments powered by Disqus