Modeling Functions from an Object-Oriented Perspective


Modeling Functions from an Object-Oriented Perspective

Before object-oriented analysis and design methodology captured the imaginations of software developers, the primary methods they used to ply their trade either emphasized the functions (the behavior) or emphasized the structure (the data).

Actually, the most common technique was (and still is) hacking—in effect, a mostly undisciplined, unrepeatable approach—but styles of hacking continue to evolve, influenced by fashionable programming languages, concepts, and other fads of the day.

The predominant style then separated out functional development (analysis, design, and implementation of the behaviors) from that of structural development (analysis, design, and implementation of the data). That is, people designed their behaviors (the things the system does) independently from that of their data structures (the values, fields, records, and database that contain the data of the system).

These approaches worked, but they tended to result in fragile, hard-to-maintain systems. Someone always wanted to change a behavior (which was on one set of models), or change a data structure (which was on another set of models)—without seeing both views—and with no encapsulation or information hiding to limit complexity, the system usually broke. Every change propagated ripple effects that could change everything else. (For more about encapsulation, information hiding, and other good development principles, review Chapter 2.)

Object-oriented techniques help you address these problems by keeping an eye on some aspects of the functional view (seeing the operation in terms of behavior and control) and the structural view (focusing on objects) at the same time.

UML tries very hard to prevent this dangerous decoupling of behavior and data. Because UML arose from the principles of object-oriented development (such as described in Chapter 2), it presents a unified view of behavior and the objects that do the behavior. Each diagram type may emphasize one or another aspect of the system, but no diagram type is exclusively functional. In Table 11-1 (in the next section), we show some of the modeling techniques you can use when you need to concentrate on the details of a behavior.

 Warning   You can’t get away with ignoring the objects that do the behavior and considering only the objects that the behavior works on. There is no pure functional diagram in UML.

When use cases aren’t enough

Often your use cases will be simple behaviors of your system. The text-based approach to their documentation, as explained in Chapter 9, will be sufficient to document their externally visible behavior. Your use-case courses—the main course and the alternate course(s)—describe a set of interactions between an actor and the system. It’s simple when there are only two objects. However, you may have secondary actors involved, in which case your interactions can get complicated with three or more participating objects. You also may have many alternate courses, or alternate courses of alternate courses. You may find the simple text-based main and alternate course approach sufficient for requirements understanding, but you will be challenged to use it to help in design.

UML has several possible approaches that might help you in explaining the details of behavior. We outline the different approaches in Table 11-1 and give you some idea of their domain of suitability. You might use any of them to capture the use-case flows graphically, which can help you in designing them—and understanding them. Often you need more than one modeling approach to properly clarify the behavior of interest. These techniques are available for exploring the details of any behavior, so you can apply them to use cases as well as operations in your work.

Table 11-1: Functional/Behavioral Modeling Techniques

Technique

Indicates . . .

You’ll Find more Info . . .

Use case diagrams

Externally visible behavior from actor’s point of view. Covers all scenarios at the same time, may call out some variations graphically . Good for high-level overview and under standing and specifying requirements.

Chapter 8, 9, and 10 (and later in this chapter)

Operations (Class diagrams)

Name, signature, arguments. Good for simple presentation and showing how to call behaviors on objects.

Chapter 3 (and later in this chapter)

Sequence diagrams

Participating objects, exchanging events. Usually a single scenario at a time. Good for application analysis and system design.

Chapter 12

Activity diagrams

Ongoing activities, concurrency, data flow. May cover several scenarios at a time. Good for capturing and designing repeating or concurrent activities, or finding target objects for lower-level behavior.

Chapter 13

Communication diagrams

Detailed operation design playing out over static structure. Usually a single scenario at a time. Good for capturing and designing complex perations, algorithm design, and design patterns.

Chapter 14

State diagrams

Response to complex events. Usually covers all scenarios at the same time. Good for capturing and designing event driven behavior or state machines.

Chapters 16, 17, and 18

Text-based specifications

Flows and scenarios. Constraints, pre- and postconditions. Usually covers all possible scenarios. Good for requirements specification, mathematical algorithm design, language-independent programming. Often used along with other techniques.

Later in this chapter

One reason that you will find these techniques useful for all sorts of behavior is that use cases may describe behavior offered up by any class-like entity in UML. For our purposes, the subject of a use case may be a system, subsystem, class, or a component.

Describing behavior with use cases

As we explain in Chapter 8, use cases describe the behavior of the system as seen from the actors, who are outside of the system. The actors consider the use cases as the system’s operations. Figure 11-1 shows part of a use case diagram for the Hotel Reservation System. Any model element in UML that exhibits behavior can be the subject of a use case, so you can describe the behavior with use cases at any level.


Figure 11-1: Use class of a system.

 Tip   We recommend that you draw use case diagrams for the system as a whole. We also recommend that you draw use case diagrams whenever you find you have a complex subject that needs to be treated as a black box, where the external and visible behavior needs to be specified, but the internal behavior is hidden. You’ll find that this will apply to all systems, because you need to distinguish the testable, required (visible) behaviors that the users want from the designable (hidden) insides that you want to develop.

In larger systems, this need for use cases will also apply to subsystems. As you decompose the system into subsystems, these subsystems can be treated as use-case subjects. Their actors will be those entities that are external as you look at each subsystem in turn. For example, the top part of Figure 11-2 shows a piece of the Hotel Reservation System context diagram—emphasizing the system and its surrounding context. They are good for quick communication of what in and what’s out of the system. The bottom part of the same figure shows the results of portioning the complex system into three simpler subsystems (User Interface, Business Logic, and Persistent Store).


Figure 11-2: System decomposition showing lower-level use-case subjects.

When you do this type of partitioning, treat these subsystems as the subjects of their own use cases with their own actors. The actors of the User Interface subsystem are the original Potential Guest and the neighboring Business Logic subsystem. From the Business Logic subsystem point of view, you would treat as actors the User Interface subsystem and the Persistent Store (DB) subsystem. (By the way, the tuning-fork symbol in the upper-right hand corner is the optional UML icon for the «system» or «subsystem» stereotype—some tools will use it and some won’t.)

As with the subsystems, you may find that documenting with use cases would even apply to lower-level decompositions, either to the behaviors of lower-level subsystems or to the behaviors of large components or classes. This is most useful for you in the larger development efforts where different development teams may be assigned these large components and classes. You’ll be taking advantage of the suitability of use cases for separating requirements from internals, when you use them to spec out (specify) the requirements for each development team. For another look at this sort of leveled decomposition, see Chapter 8.

Converting use cases into operations (class diagrams)

To map use cases directly to system level operations, you can start by converting all directly actor-accessible use cases to public operations on a class representing the system. Remember, operations are behaviors that a class may be asked to perform. They must be public because they are visible to the actors.

You typically convert other use cases—such as included use cases (connected by an «include» relationship) or extended use cases (connected by an «extend» relationship)—to private operations—while they are behaviors the system needs to perform, they can’t be invoked directly by an actor. If you were to convert the use cases from Figure 11-1 into and use the UML notation for operations and visibility that we explain in Chapter 3, you would arrive at the system as shown in Figure 11-3. Remember that the + sign indicates public visibility, and (you guessed it) the – sign indicates private visibility.


Figure 11-3: Use cases as system operations.

Converting the use cases to operations is really one of the first steps you can do to design your system. It’s simple, but it’s a start at identifying the operations. The next step for each operation in Figure 11-3 would be to add the operation’s return type and arguments, and the arguments’ types, directions, and default values.

Figure 11-3 shows these details for the guaranteeReservation operation indicated in bold. From the description of the use case in Chapter 10, it is clear that this operation needs to be passed a price and card information for use by the Credit Card Authorization system. We choose estPrice:Money and aCard:CardInfo as the arguments and their types. They are shown in the argument list of the guaranteeReservation operation in the figure. We also determined that the including use case, Make A Reservation, would need to know if the guaranteeReservation use case was successful, so we indicated a Boolean (True/False) success flag to be returned from the operation.

If you continued with this design, you would define the details of CardInfo, which includes, at least, HolderName, CardNumber, and ExpirationDate, in a separate class box called CardInfo using the techniques of Chapter 3. We won’t do that here. You might also find that the operation needs other information or returns other information—if so, capture them as input or output arguments to the operation. When you do this design, you may come up with slightly different results, but go ahead, it’s your design.




UML 2 for Dummies
UML 2 For Dummies
ISBN: 0764526146
EAN: 2147483647
Year: 2006
Pages: 193

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net