UML for the Software Developer, Part 1: Building Classes

hy do we need to model software? After all, aren’t the acts of coding and refactoring of that code enough? That depends on what is meant by enough! You could code up some software, hand it in, and go through a constant refactoring process with the client. This is how most software is developed today. However, times are changing. A decade ago, a game would have been developed by a single developer in the basement. Graphics were primitive and it was enough to produce a few sprites, some cute screens, and an occasional story line.

Today it takes a team of experts. Graphics gods, story tellers, and code gurus all come together to develop the newest and latest games. The bar has been raised. This is the future of software development?the developer will be joined by requirements experts, GUI masters, and software designers/architects. The teams that operate this way will raise the bar for the client, just as in the game industry. Communicating in bits, bytes, and code will be replaced by a common language, from requirements and design to coding and transition. Code will be developed from common models to meet the client’s requirements and needs. This is why you need to know something about modeling software.

Modeling software requires a standard language. This is not a new concept, but until recently there were many standards from the structured diagrams of IBM, Data-Flow, IDEF0, OMT, and Yourdan, to the dozens of other modeling standards. Today one language is fast becoming the standard. The Object Management Group (OMG) has adopted the Unified Modeling Language, or UML, and it is approaching critical mass for becoming the only standard for modeling software. (See the sidebar, “A Brief History of UML“)

UML for the Software Developer
While UML has 16 different diagram types for modeling, we will concern ourselves with only three. Each of the three modeling diagrams represents a different facet of software and they work together to complete a picture.

In object-orientated design and development we focus on classes, their behavior, and how they relate to reality. In UML, these three areas are represented by static diagrams, behavior diagrams, and physical diagrams respectively. In this article we will focus on class diagrams. The first part covered here will look at how classes are represented in UML and how they relate to code. The second part (which will be in the next article) will cover how the classes relate to one another.

Class Diagrams

Figure 1. Brokerage Class: This first-iteration example class captures the base functionality needed for the application, but pools all the methods in one large Brokerage class.

Class diagrams are usually the first diagrams taught for UML. They represent the static view of how classes interact. They are also the most familiar to software developers. Class diagrams are composed of classes, and those classes represent the same functionality as classes in Java, C#, or C++. A box containing the class name, methods, and attributes represents each class.

In the following sections, you will be looking at a hypothetical brokerage business, RichMen Inc. RichMen is a very simple brokerage firm that has clients?and brokers buying and selling various securities for them. RichMen wanted a system to track which securities are bought and sold for each client, by each broker.

Iteration 1: The Brokerage Class
The first thing that we look at is how to store and retrieve securities, brokers, and clients. When we get to how the classes are related we will add buying and selling. For now we need to know the names of the securities, who the brokers are, and the firm’s clients.

In Figure 1, we see our first iteration of the class. The top part of the box contains the name of the class, which in this case is simply Brokerage. Beneath the class name are the attributes of the class Brokers, Clients and Securities. A dash () precedes each attribute. This symbol signifies that the three attributes are all private to the class and not exposed to the outside world. After the attribute names we have a colon followed by char[] [1..*], which translates to an array of one-to-many strings where [1..*] is the multiplicity qualifier. The bottom of the box contains the different methods of the class: AddBroker, AddClient, AddSecurity, DeleteBroker, DeleteClient, DeleteSecurity, ListClients, ListBrokers, ListSecurities, and GetQuotes. The plus symbol (+) in front of each method tells us that each method is public and exposed to the outside world. After the method name you have the parameters, which are the same as expected if this were code followed by a colon and a return value. In the list methods there is one problem?char* in C is a pointer to some characters. What is needed is some way to point to many strings and not characters. Most modeling tools support types like string in UML, but in this case it’s assumed that they don’t.

Iteration 2: The Collection Type

Figure 2. Enhanced Brokerage Class: In this second iteration of the Brokerage class, the char[] type has been replaced by the String type and the char* has been replaced by the Collection type.

In Figure 2 the char[] was replaced by the String type and the char* was replaced by the Collection type. In the .NET languages, these types are part of the native language?they are part of Systems.Collections. In the examples, ArrayList was used instead of the more abstract CollectionBase.

So in practice, you declare these types in UML and do not display them with the class diagram itself. If you look closely, you’ll see I added the collections to the Brokers, Clients, and Securities attributes. This makes sense from a coding standpoint as well, but why did I leave the [1..*] and [0..*] qualifiers next to the collection? This is our first example of how modeling differs from coding. I used the qualifiers to specifically declare that the Brokers and Securities collections must be initialized with at least one element.

The Clients don’t need to be initialized. Why do I do this? In developing this system you need at least one broker to do anything with the system. The broker would need at least one security to buy or sell, but it isn’t until he buys or sells the security that he then needs to give it to the client. In the current class you are just adding, deleting, and listing the brokers, clients, and securities, but in a real system you would want brokers to buy and sell securities for their clients. One could argue that the SEC requires that the broker have a client before he buys or sells a security, but from a system standpoint it doesn’t matter if the client exists before or after buying or selling a security.

It wouldn’t be difficult to implement this class in C#. If the UML tool that you are using generates code, then it might generate something like this:

using System;using System.Collections;public class Brokerage{     // Generated Code was refactored for readability.  The “Using” statements were      // added by hand. Return statements are also added in most of the modeling tools but     // removed here.      private ArrayList Brokers;      private ArrayList Clients;      private ArrayList Securities;      public Brokerage()      {             InitializeComponent();       }    public void addBroker(String Name){ }    public void deleteBroker(String Name) {}    public ArrayList listBrokers() {}    public void addClient(String Name) {}

The only thing that needs to be done from this point is to add some implementations to the code and you have a class that you can hook up to a GUI and voilà!

Iteration 3: Namespaces and Refactoring

Figure 3. Refactored Classes: The brokerage class is broken down into three classes Broker, Client and Security.

If you look closely, there are already a couple of issues to think about. You have developed in anti-pattern parlance the “god” class?one that does everything. As experienced developers, this should immediately set off some mental triggers.

If this were all in code you would be refactoring the code by now, making changes to separate out the different concerns into their classes?in some cases writing new tests, putting in a new test harness and figuring out how to combine these classes together to hook back up to the GUI. This is quite a bit of work.

In this simple case, you would immediately recognize that there are some separate concerns here and develop them from the beginning as separate classes. However the temptation would be to hook every class into the GUI directly. If you were really good, you might see this problem immediately and build some type of class that would combine the three classes together, but that requires some forethought. UML provides us with an easier way to do this without the work.

In Figure 3 the brokerage class is broken down into three classes: Broker, Client and Security. You encapsulate the classes in the package Brokerage. In .NET you represent packages as namespaces. A namespace is a nice construct for separating the different concepts of an application or system. One can think of a namespace as a logical component.

namespace Brokerage{       public class Broker        {        }       public class Client       {        }       public class Security        {        }}
Figure 4. Class Using an Interface: An <> stereotype is the way to identify different types of classes using UML.

If you look closely you notice that all three classes have the same operations, and more importantly, they all operate on collections. This should trip yet another alarm?you can refactor this class to reduce the duplicated logic.

From a UML standpoint this will be easier when you start adding more methods to the classes. In UML you accomplish this using the <> stereotype. A stereotype is the way to identify different types of classes using UML. They can be user defined like <> or specific to UML like <>.

The <> stereotype in BrokerageCollection accomplishes two things. Every class that uses this interface will have the exact same functionality for using collections. It also simplifies the diagram. You may wonder why the classes inherit from an interface and not another class. Inheriting from a class would have allowed me to add Brokers, Clients, and Securities to BrokerageCollection (interfaces don’t have attributes like classes do) but .NET languages (except for C++) do not allow for multiple inheritance from classes, so the interface was used instead. If you wanted Broker to later inherit from a Person, for example, this would be impossible if BrokerageCollection were not an interface.

using System;using System.Collections;public interface IBrokerageCollection{     void addMember (String name);     void deleteMember (String name);     ArrayList listMembers();}

Two notes about the interface method. First, the public interface in code is IBrokerageCollection and BrokerageCollection in the model. My preference is to not use the “I” in front of the interface for modeling but if code generation is part of your modeling effort then it is a good idea to add the “I”.

Second, in the example it could be argued that the System.Collections.ArrayList library class already has a method for adding, deleting, and listing members. There might, however, be other validation that is happening within the classes themselves. Specify that only strings can be added or deleted, for example. Validate on the number of characters or maybe restrict the brokers to specific identifiers rather than the names. You could also inherit three different types from System.Collections.ArrayList; BrokerCollection, ClientCollection, and SecurityCollection. In modeling, as in coding, there is often more than one solution.

I have covered how a UML class relates to code, but not yet how they relate to each other. You can easily see that it’s cheaper?from a time perspective?to make changes in the class rather than in the code. In the next article I will cover how the classes interact. You will see how to use UML models to have the brokers sell the securities for their clients. Exciting stuff!

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Related Posts