ccording to Clemens Szyperski (author of “Component Software?Beyond Object-Oriented Programming,”), software components are binary units of independent production, acquisition, and deployment that interact to form a functioning system. He continues to add that a software component can be deployed independently, is a unit of third-party composition and has no (externally) observable state. In UML we use component diagrams to break down systems into understandable chunks that show the dependencies between components.
In this article I’ll use component diagrams to link the class diagrams I discussed in earlier articles (see part 1, “Building Classes,” part 2, “Mastering Associations,” and part 3, “Aggregating“) with the “Deployment Diagrams” in Part 4.
Component diagrams in UML capture the essence of how components interrelate with each other. Each diagram consists of only three different elements: components, interfaces, and dependencies. Components are composed of interfaces to other components as well as dependencies, which show how the components depend upon each other.
Component diagrams differ from class diagrams in how software is represented. In a class diagram the implementation of the classes is source code (which is why code can be directly generated from a class diagram). In component diagrams executable code is represented, which is closer to the deployment diagrams I looked at in the part 4.
Class diagrams show relationships that represent the association between classes from the simple bidirectional association to the more complex compositions and aggregations shown in “Mastering Associations.” Component diagram rely on dependencies for component relationships. Dependencies differ from the class associations because associations are references from one class to another and can be bidirectional whereas dependencies demonstrate the dependence of one component on another component. If a component with a dependency is missing, the missing component is added to the Global Assembly Cache (GAC) but nothing else is inferred.
![]() Figure 1. The Different Component Elements: Each component in the example has a stereotype that represents what type of component it is and tags describing the vendor (proprietary is the same as in-house), the language (where applicable), and the version of the component. Dependencies point from the dependent class to the class that it depends upon. The interface will usually have a name, which in some cases will be a method call. | ![]() Figure 2. Simple Component Diagram for Richmen, Inc.: Notice that with only six components the diagram is complicated. PortfolioVision displays portfolio statistics, StockVision displays current stock information, Portfolio calculates the client’s portfolio value and QuoteData, CustomerStockData, and NewsFeed manage the data inputs. |
In class diagrams interfaces are treated as separate classes, which are implemented through their associations with other classes. In component diagrams the interfaces are an integral part of the component and are not always displayed.
Figure 2 is one of the component diagrams for Richmen, Inc., a fictional company used through this series of articles. The diagram is complicated even with only a small number of components. In systems where there are 100+ or even 1,000+ components the complexity of component diagrams is mind-boggling. Validating the diagram for any architectural problems is almost impossible. PortfolioVision depends upon both Portfolio and QuoteData. In the context of the other four components is this good or bad? Are there any obvious architectural problems?
Fortunately there is an easy and organized way to view a component diagram. In the following section I will show this solution using architectural patterns.
Architectural Patterns
In an earlier article (“Mastering Associations“), patterns were mentioned in the context of design patterns. Design patterns are used at the class level for repeatable solutions to common problems including the Factory, Singleton, and Strategy patterns (as described by the GOF in their book “Design Patterns“). As mentioned, class diagrams model classes and the associations between them and it follows that design patterns are used in the same fashion.
Architectural patterns, on the other hand, are used at the component level, relying on components and their dependencies. Examples of architectural patterns include monolithic, two-tier, three-tier, n-tier, layered, pipes and filters, hierarchical, broadcast and listeners, switchboards, and MVC. In this article I will only cover two: three-tier and MVC. (For more information on the other patterns, “UML Applied: A .NET Perspective” by Martin L. Shoemaker is a simple guide, while “Pattern-Oriented Software Architecture: A System of Patterns” by Buschman, Meunier et al. is the standard reference.)
Architectural patterns provide a method of organizing and evaluating components. In many cases the patterns are not directly visible and a couple of different architectural patterns may be tried. Each architectural pattern organizes the components in a different fashion emphasizing the architectural qualities of scalability, reusability, modifiability, and other “-ities.”
In the Richmen, Inc. example I want to see if there are any problems in the architecture and whether I can solve them. I will start with the three-tier pattern and see if it answers any questions (see Figure 3).
![]() | |
Figure 3. Three-Tier Pattern Applied to the Component Diagram: Each tier is represented in UML by a package: in this case Data Tier, Application Tier, and Presentation Tier. The tiers are used as holders to help organize the components. |
The three-tier pattern houses the components in three different groups or tiers named data, application, and presentation. The components in one tier are independent of the other tiers and depend only on the components in the next tier down. Advantages of this approach are that 1) the components can be modified without effecting components in the other tiers and 2) the components in the data tier can have their database connections pooled with the database-specific logic limited to only one place. The presentation tier contains the components that are necessary for viewing the application, the application tier contains the components that implement the business logic, and the data tier coordinates the connections to the databases.
In the Richmen, Inc. example the components don’t follow the three-tier pattern. StockVision and PortfolioVision depend upon quote data and StockVision also depends upon the Newsfeed. This violates the rule that that the components in one tier can depend only on components in the next lower tier. If I add a new data component for PortfolioVision I would have to modify both the PortfolioVision component in the presentation tier and the Portfolio component in the application tier. If I followed the three-tier pattern then only the Portfolio component would have to be modified.
PortfolioVision shouldn’t care where the data comes from. This fact is easy to see but how about the fact that both PortfolioVision and StockVision depend upon QuoteData directly? Can I add a component in the application tier to access QuoteData for these two presentation-tier components? Do I need two components? This pattern doesn’t lend itself to answering these questions. Maybe another pattern would answer these questions.
The MVC Pattern
I will use another architectural pattern, the model-view-controller (MVC) pattern, to see if it can answer any architectural issues better than the three-tier pattern.
![]() | |
Figure 4. MVC Pattern Applied to the Component Diagram: The containers are in different positions than in the three-tier example. |
The MVC pattern separates components into three packages: Model, View, and Controller. The model has the components that use and rely on the underlying data. The view houses the user interface components. The controller contains the components that control which view is being displayed. The model notifies the view about any changes in its data, contains the current state of the application, and responds to any queries about its current state. The view renders the model, request any updates from the model, sends any user events to the controller, and lets the controller select the different view. The controller defines the application behavior, maps the different user actions to model updates, and selects the view. (For a good discussion of the GUI implementation of Model-View-Controller look at “Enterprise Solution Patterns Using Microsoft .NET” from the Patterns and Practices series of books from Microsoft Press.)
In the Richman, Inc. example the use of MVC is easier to read. In the MVC pattern every dependency must point to the model components, which is the case in this example. QuoteData, NewsFeed, and CustomerStockData inform the StockVision and PortfolioVision components about changes in their underlying data. StockVision and PortfolioVision handle the rendering of the user interface. The only problem with StockVision and PortfolioVision is that they also operate as controllers by handling any user requests.
![]() | |
Figure 5. Richman, Inc. After Refactoring Using MVC: The stock component and two- way dependencies between the controller and view components are shown. The view components pass the user actions to the controllers that notify the model to change the view. |
If it weren’t for Portfolio this would be a classic Document-View architectural pattern. The controller and the view components are tightly coupled but the data components are not. The benefits of this are similar to the tier benefits. The data components, their connections, and data-access logic are separate from how the user actions are handled. The Document-View architecture was used so often is it was an implicit part of Microsoft’s C++ compiler.
Should I remove the Portfolio component and move the business logic into the data and presentation tiers? If I split the logic this way, then the presentation tier would handle all of the control logic and the business logic used to transform that data into a viewable screen, and the data tier would be used to calculate aggregate values for the portfolio. The other choice would be to not use the Document-View architecture and change the Portfolio component to MVC. This would require PortfolioVision to pass any button clicks or user interface calls to Portfolio. Portfolio would react to the user interface calls informing CustomerStockData and QuoteData that there is a request to change the views. StockVision has less business logic than Portfolio and PortfolioVision but still has a dependency on QuoteData, which is now part of the MVC pattern. It would make sense to create another component called Stocks that would act in the same fashion as PortfolioVision. This would not confuse the use of QuoteData in Portfolio and StockVision.
In Figure 5 the components are refactored. From an architectural standpoint the design is stronger than before. The model data can be verified and checked without relying on the business logic in the controllers or the GUI logic in the views. Views can be added without changing the model components and the view components are not locked into the specifics of how commands are handled. If we added the command pattern to the controller even the commands could be changed dynamically. When looking at all three example diagrams it is much easier to follow the dependencies after Richman, Inc. was refactored.
How Components Exist in .NET
The last topic that I want to discuss is how components are implemented in .NET. In my first article, “Building Classes,” I discussed namespaces. I showed how a namespace is nothing more than a programmatic way to prevent naming collisions by prefixing variables with the same names with a namespace. From an architectural view a namespace can be used to identify parts of an architectural pattern. In the case of MVC there would be three namespaces:
namespace Model { } namespace View { } namespace Controller {}
The namespaces in .NET can exist across classes and assemblies so that multiple components can be added to an assembly. Assemblies are the same as components. Each assembly contains one or more portable executables (PEs) that contain multiple classes compiled into MSIL (Microsoft’s intermediate code). The assemblies also contain a manifest that tracks the variable names, the number of classes, types, and metadata for the assembly.
In the Richman, Inc. example I could add each component to its own assembly but use the appropriate namespace across the components in the model, view and controller. It is also possible (although it cannot be done through Visual Studio) to add more than one component in each assembly and have three assemblies for model, view, and controller respectively. Depending upon the size of the program it is best to remember that the fewer the assemblies the easier it is to deploy.
So far I have gone from class diagrams to deployment diagrams. The link between the abstract classes and how they are deployed are components that contain multiple classes and are grouped logically so that they can be deployed. The final article in this series, coming next month, will cover sequence diagrams.