UML for the Software Developer, Part 3: Aggregating

UML for the Software Developer, Part 3: Aggregating

n Part 2 we looked at associations, which are nothing more than references, but they can be directional and represent multiplicity. If we were restricted to our ability to generate code using UML this would be sufficient. If we are offering guidance on how the application should be built, as well as auto-generated code, we need something more.

To continue with examples from the previous articles, your friends at Rich Men, Inc want to start tracking what stocks they buy for their clients. Ideally they would somehow offer some aggregated values for all of the stocks that a client has in order to boost their value to the client.

Iteration 1: Starting with a Few Associations
One rule that I follow when designing an application is to always start with the associations and the base classes. In order to avoid making any implicit assumptions, inheritance, the use of aggregation and composition, and even the multiplicity relationships are all saved for a later iteration.

For the purposes of this article you aren’t concerned with the storage and retrieval of these values, as you were in the last article. The client owns the securities so it is one directional and you can make the assumption that a client owns more than one security. Other attributes include the number of shares of the security and its current combined dollar value. I also added an operation called AddTrade that will allow us to add to both the quantity and the value of the security.

Figure 1. Associating the Client and Security Classes: Notice that Client and Security are individual classes, not members of a collection.

Seems complete! You have a client who owns some securities, can get the values of the securities and even add to them (for now let’s assume that AddTrade can represent both the buying and selling of shares of a security). The only thing missing from this story is the value of all the securities. This should be simple as well. Add a TotalValue attribute and an operation CalculateValues that would run through all the securities and add their values up and the story should be complete.

But there is a problem with this approach. You refer to this as SRP or the “Single-Responsibility Principle.” A class should have one, and only one, purpose. This is what prevents the “god-class” anti-pattern. If your client class uses the class to hold the total values of the securities it would violate SRP to use the class to track the client’s relationship as well.

Iteration 2: Using SRP
To preserve SRP in the client class you will create an intermediate class called Portfolio. The purpose of Portfolio will be to maintain the total values of all the clients stocks. You added a new type of associations between these classes, this is called aggregation in UML and is used in cases where one class owns another class. In Ontology this ownership is called a part-whole relationship. Aggregation is used this way to show that a client owns a portfolio and that the portfolio contains securities.

Figure 2. Adding a Portfolio Class: Adding a Portfolio class creates the “separation of concerns” that you are looking for. You added a type attribute to security with a default of “Stock” to allow differentiation between different types of securities. The lines with the filled in diamond represent composition, with the parent class having the diamond attached, and the child class being the other end.

In MDA (Model Driven Architecture) the trend has been to display aggregation using regular unidirectional associations. As mentioned, from a coding perspective there is no syntactic difference. However, from a semantic view there is a difference. In the current example you know that only the client can access the portfolio. If this relationship was just an association this would not be clear. In fact, the type of aggregation used in the example is referred to as composition and only allows for single ownership.

Iteration 3: Adding Live Quotes
To value a portfolio requires some stock quotes. You could type the quotes in by hand, but in most cases the quotes are pulled in from some external system. The manner of representing aggregation has changed in the example. It has become an unfilled diamond as opposed to the filled ones in the other aggregations. This is the standard form of aggregation and is a weaker form than the composition that you used earlier. Ownership is still present but this form of aggregation allows for multiple owners. If this were represented by an association line, you would assume that the portfolio references the quotes in some fashion. By using aggregation you know that the Portfolio must be a subscriber to the quotes, not just have some relation to them. While this difference may not seem like much it will effect the supporting classes to these quotes are coded. As noted, if you auto-generated the code for this there would be no difference between associations, aggregations, and the stronger form of compositions.

Figure 3. Adding Live Quotes to the Portfolio: Notice the use of the <> stereotype for a system that exists outside of the current system.

The CalculateValue method of Portfolio would be changed to incorporate these quotes. You could add the following:

public double CalculateValue{    totalValue =0;    for each Stock in StockCollection    {        double qt = Quotes.getCurrentPrice(Stock.Name);        totalValue + = (qt-Stock.Value) * Stock.Quantity;     }        } 

The assumption made is that every trade conducted for the client was done at the same price. There are a couple of ways of handling this. You could use some type of averaging scheme to come up with an average stock price in Security.addTrade. Another solution would be to loop through all the trades and perform the calculation against the new quote. We can leave these details to the user.

You do have one more bit of refactoring to do. In the sample you had a variable for StockCollection. You also need to replace the Client collection that was lost when you used the Client class to represent one client.

Iteration 4: The Last Iteration
In the final iteration you added a Customers class to hold all the clients. You also added the Trades class for all the trades done for a particular client. When these class diagrams get large it is common to not add all of the attributes and operations. ClientCollection, StockCollection and TradeCollection are usually assumed and sometimes represented by multiplicity indicators on the class relationships. The AddTrade method could be left out as well, since the Trades class would require that method in Security as well as other CRUD (create, read, update, and delete) methods. Another practice seen in many diagrams is the UML modeler?either using all composition relationships or all regular aggregation relationships.

Figure 4. Adding the Trades and Customers Classes to the Final Iteration: The ClientCollection, StockCollection and TradeCollection attributes are not always explicitly represented.

There are some other assumptions that could be made. The Quotes class requires a subscription method. One could change the Quotes class into an interface and use this as a generic method for plugging into any quote provider. The client may want to see the quote for a current stock to see if he wants to make a trade. Do you use the Portfolio class for this or do you instead have the Client class register directly with the Quotes class?

A final note: I put a getValuexQuantity method in Trades. This method multiplies the price paid for the stock by its quantity (yet another assumption that the trade was made at one price). In this case, the equation for the stock value might be calculated in the following way:

Security.Value = 0;Security.Quantity = 0;For each trade in TradeCollection{      Security.Quantity = trade.Quantity;      if (Security.Quantity <> 0)      {                   Security.Value = trade.getValuexQuantity() / Security.Quantity;       } } 

That will give an average weighted value for all the trades for that stock. If you didn’t need to maintain the trades at all, then you could even eliminate the Trades class and use the above calculation as a static average weighted value.

Final Thoughts
To recap: associations can represent ownership using aggregation if ownership is shared and composition it there is only one owner. If you auto-generate the code, you can not tell the difference, but in a large system there is often a difference between aggregation and composition (whether something is a utility class or attached to a specific class, for example).

Author’s Note: In many books, composition and aggregation are determined by the lifetimes of the objects not just the ownership. Ontology, however, deals with the semantics as related to classifications, not specific cases?in other words, classes and not objects. It is more correct to think in terms of ownership, which is more consistent with how whole-part relationships are represented in ontology. The UML Reference by the Three Amigo’s discusses some of this in detail.

This completes your foray into classes?hope the trip was eventful. The examples were simple but contain the elements that you will find in every class diagram. In the next article, I leave the world of static diagrams and move on to diagrams for deploying the results of these diagrams on a system.

See also  Essential Real Estate Tech Trends: Innovations Every Agent Must Understand

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist