What is the best way to map an UML component to C++?

Viewed 561

I have an UML component diagram, in which every component is "connected" to other components either by providing them certain interfaces or by requiring interfaces provided by other components (they are connected using the classic "lollipop" notation).

At a lower level of abstraction, every component I cited before is described by a class diagram.

I know how to map the UML classes contained in every class diagram to C++, since the language has the concept of class in it.

So my question is: what is the best/most common way to map the concept of UML component to C++ in a situation like this?

Web resources dealing with this particular subject are also welcome.

Edit:

I know there isn't a final answer given by UML, I am more interested in knowing how do practitioners usually deal with this problem. What is the state of the art?

2 Answers

What's a component?

A component is a self-contained, replaceable piece of software that offers some functionality based on exposed and consumed interfaces.

The UML component (see Bruno's answer) models such a component, but without clarifying what design-time or a run-time replacement shall mean. The inventors of UML clarified in their book Unified Software Development Process that UML components should in principle belong to the implementation model, that:

describes how elements in the design model, such as design classes are implemented in terms of componenets such as source code files, executables an so on.

What's a component in practice?

In their book, Jacobson, Booch and Rumbaugh added some practical component examples (and I added here a short comment to map interfaces):

  • an executable: Its interface may correspond to an API and message or data formats
  • a library: Its interface is the definition of the library objects and it's exposed via symbols)
  • one or several source code files: Its interface is the interface mechanism of the programming language. You may for example have C++ source code components;
  • a database table: Its interface is defined by the DDL, the specifications of the query language and/or the DBMS API.

How to implement components in C++?

How to implement a component and its interfaces is left completely open: a C++ component could just be an ordinary executable that playsa well defined role in a bigger puzzle; or a library.

This makes your question very broad. However, if we narrow down the answer to source-code components in C++, we can go further.

At a "higher level" of the source code ("higher" means: "I use my file explorer and do not look into the files"):

  • Typically, an interface is defined in one or more C++ headers. In headers you can declare functions or define classes, without providing an implementation.
  • A C++ component can be one or a group of several translation units (i.e. source code file). These can be located in their own directory, but they do not need to.
  • A component consumes required interfaces by including the corresponding C++ headers. It provides its own interface in form of one or several headers that can be included elsewhere.
  • Important remark: I arbitrarily reduced the problem to whole source files, but in reality, nothing prevents you to group several components in the same source file. It's just that in practice this makes components less interchangeable: this is why I don't mention it.
  • It's not excluded that in future, more and more the C++ components will look like C++ modules (feature of C++20).

The interchangeability of such a source component can be achieved by replacing implementation files that offer a different implementation for the same interfaces defined in the headers. This interchangeability can only happen at implementation time.

At a "lower level" of the source code (i.e. looking in the source files) you also use C++ language features to make components that can be replaced at run-time independently of the source-code organization:

  • language features and programming practices can define interfaces
  • a interface can be defined, for example as a class definition, or better, as an abstract class that is then specialized into many alternative components which all comply with the interface via inheritance.
  • a reference, a pointer, or (preferably) a smart-pointer can be used to consume the interface, allowing to select the suitable component at runtime, e.g. using a factory.

But all this is as always simplified: you have also another powerful form of componentization in C++: templates. Templates are a compile-time componentization and independent of the source code structuration:

  • Templates can define the provided interfaces in headers. Unfortunately, the implementation can only difficultly be separated from the implementation, unless you use headers in headers (see boost library as a very robust example).
  • Templates consume the interfaces of all the types they use. Unfortunately, it's an implicit definition of the required interface.

Conclusion / advice

Even narrowing down your question, there are plenty of ways ti implement components in C++. To be honest, I tend to use components mainly for high level executable components, and for sketching the architecture, but not for modelling detailed implementation at class or file level. If I'd have to change my models every time I need to include a new header, I'd soon be so busy documenting the changes, that I'd not deliver anymore, and I still value "working code" over "comprehensive documentation" ;-).

The UML components do not have vocation to be (directly) mapped in C++ nor other languages, contrarily to their 'implementation' being the artifacts for instance in that case through a library or a simple object file.

The main point concerning the component as said in the norm § 11.6.3.1 :

A Component is a substitutable unit that can be replaced at design time or run-time by a Component that offers equivalent functionality based on compatibility of its Interfaces

Related