UML 2 For Dummies


You organize a system into subsystems. A standalone subsystem, autonomous and modular (relative to the bigger system), is known as a component. UML components are like replaceable parts—you take one out and fit another in its place. We like components because we can replace it without having to change anything else in my system. Components make your systems more flexible, maintainable, scalable, and reusable. Components come in many shapes and sizes. Subsystems are one example of a large component. A complex class with many internal parts and external interfaces could also be a component. (Remember a component is a replaceable part.)

When you construct replaceable components (parts), be sure to carefully define the boundary of the component. You define the boundary by clearly describing the responsibilities and interfaces of the component. Such parts are easy to make because everyone knows exactly what the component should do. This improves productivity and makes the component easier to test (the testing teams know exactly how the part is supposed to work), which improves quality. Also, the more a component is reused, the more trustworthy and reliable it becomes.

For your components to be replaceable parts they must have the following criteria:

 Remember   You can think of a component as a subsystem with internal classes that work together to realize the publicly stated interfaces.

Logical versus physical

The experts talk about logical data models, physical models, logical views, and physical elements. You needn’t worry about all this babble. When the experts use the term “physical,” they are referring to something in the real world that all of us experience. The experts use of the word “logical” simply means conceptual.

For instance a physical table model (also known as a physical data model) describes the tables of a relational database as they physically exist in a database. The actual names of the table and its fields are used in physical table model. On the other hand, the logical data model describes the tables in a more generic or conceptual way—as entities. Entities are the concept behind the physical tables of a relational database.

The logical model for an object-oriented system consists of the conceptual pieces that make up the system: subsystems, components, and classes. The physical model consists of the real parts of a system: hardware, network connections, classes with design details specified, application code, scripts, and files.

Showing black boxes

 UML2   UML 2 redefines the meaning of the “component diagram.” In earlier versions of UML the component diagram defined components as the physical implementation of your software such as executable code files, dynamic link libraries, and source code files. The component diagram showed dependencies among the pieces of your software implementation and their hardware location. The experts who developed UML ran into a little problem: While they were busy defining diagrams, we object-oriented programmers were busy with our own meaning for the word component.

We needed replaceable parts for our applications. Classes were not replaceable. We needed an object-oriented part that provided not only behavior, but also interfaces independent of how the part worked. We needed better black boxes. So, during the mid-to-late 1990s, the practical development community came up with the idea of components. UML 2 catches up with developers and redefines the concept of component to bring it in line with the idea of an autonomous replaceable unit.

You show a component as a rectangle with the name of the component inside. The component has a stereotype of «component» and (optionally) a small icon in the upper-right corner that looks like a small box with a couple of tabs hanging off. (We’re not making this up. Honest.) Because a component must hide its inner workings from the outside, it often has interfaces attached to the sides of the rectangle. Each interface that a component provides to the outside world looks like a “lollipop” (a circle on a stick) in the diagram. Each interface that the component requires from some other class or component in the system looks like a half-circle on a stick.

Figure 19-5 provides a black-box example of UML notation for a component called PersistentStore. Here it has the «component» stereotype and the small component icon on the right side. Our application component, PersistentStore, provides the following three interfaces:

Our PersistentStore component also requires access to a relational database via a specific interface. Figure 19-5 shows this required interface with a half circle (socket) on a stick called Rdbms. The Rdbms interface must be provided by another class or component in your system. The PersistentStore connects its required interface to another component’s provided interface—and both have the name Rdbms.

Figure 19-5: Basic component with interfaces.

Figure 19-6 shows another black-box example of a component. Notice that UML doesn’t make you use the circles-and-half-circles-on-a-stick notation; you can replace the lollipops with operations—showing the provided interfaces with the «provided interface» stereotype and the required interfaces with the «required interface» stereotype. The diagrams shown in Figures 19-5 and 19-6 have the same meaning.

Figure 19-6: A component as a black box.

 Remember   Your components are, in effect, black boxes. Nobody can see what goes on inside them—but everyone can see their interfaces. The software components represented in your diagram have interfaces too, no less than the pieces of electronic equipment that have tangible interfaces for hooking up various cables.

Describing the interfaces

You show components as black boxes when you want to wire them together to make up your system. In the example of the PersistentStore component in the previous section, you connect the PersistentStore to another component that provides the Rdbms interface.

But, if you’re building the insides of a component for others to assemble into their system, you have to show the interfaces’ details. If (for example) other developers want to use your PersistentStore component to retrieve data from the database, they have to know the signature of the retrieve operation in the DBQuery interface, which may look like this:

retrieve(type : Object, search : String): Object(idl)

When you build a component, give the users of your component a special interface specification using a component diagram. In this type of diagram you show the component as a black box and the interfaces as classes. Each interface has the «interface» stereotype, the name of the interface as the name of the class, and the full operation signature for each operation with in the interface. Connect up the provided interfaces to the component with a realizes dependency. The realizes dependency shows that the component implements the operations specified by the interface. Connect the required interfaces to the component with a uses dependency. The uses dependency shows that the component must use some other component that implements that interface.

Your users of the PersistentStore component will appreciate the component diagram shown in Figure 19-7. This diagram shows users of the PersistentStore component that if they want to store an object instance in the database, they must invoke the DBQuery interface with store(theObject: Object(idl)): Object(idl). Further, if they want to perform an SQL query on the database, they would use the DBQuery interface with sqlFetch(sqlString : String) : String. To keep the diagram simple, we haven’t shown the detailed signature of operations in the DBAccess, DBTest, and Rdbms interface classes.

If you refer to Figure 19-6, you can see that it shows the PersistentStore component with three provided interfaces and one required interface. Figure 19-7 shows the same thing, only it uses dependency arrows instead of stereotypes:

Figure 19-7: A component with explicit interface specifications.

Looking inside the box

But wait a minute—you want to build components, not just assemble them. You need a way of showing the insides of your component. That’s easy: just add a compartment below your component and put a class diagram there. Classes inside the component work together to accomplish the interfaces of the component.

Because you must show how the internal classes are hooked up to the component’s interfaces, UML provides some special terms and notation for the purpose:

 Tip   Whenever you design a component, create a component diagram to show its inner workings. You use such a diagram to help you explore, design, and document the best ways to wire your component. You should also create a component diagram that shows the component as a black box surrounded by interface classes, each with a detailed operation signature. Pass this second diagram out to all the developers who will be integrating your component into their system.

Figure 19-8 provides an inner structure example of the PersistentStore component. When an object outside of the PersistentStore invokes the DBAccess interface using the openDB or closeDB operation, the request is delegated to an instance of the DBManager class.

Figure 19-8: Component diagram showing internal classes.

Incidentally, the DBManager is the focus of PersistentStore—so it makes sure any business logic for the component is handled properly. The DBManager creates an instance of the checkConnection class so the component can provide the service associated with the DBTest interface. Both the DBManager and the checkConnection must have interfaces on an internal component called Connection.

You can see the use of the ball-and-socket notation in the example. The DBManager requires the connect interface that the Connection component provides. The Connection component, DBManager and Query all require the Rdbms interface. The Rdbms interface is external to the component; it must be provided by some other class or component in the system.


Категории