Day 5 Designing the System: A Crash Course in Object-Oriented Analysis and Design
Teach Yourself CORBA In 14 Days
Teach Yourself CORBA In 14 Days
- What Is Object-Oriented Analysis and Design?
- Introducing the Unified Modeling Language (UML)
- The Bank Example
With a knowledge of CORBA basics--such as the concept of the Object Request Broker (ORB) and the Interface Definition Language (IDL)--along with an understanding of the IDL language, you are ready to develop and deploy CORBA-based applications. You've already gained firsthand experience implementing a simple CORBA server and client. Now you'll design, implement, and enhance a more sophisticated CORBA application. To help you see what's ahead, the following road map is provided:
- Today you'll design the sample system, a scaled-down banking application. Because CORBA is an object-oriented architecture, this chapter will introduce you to object-oriented analysis and design concepts while working through the design of the system.
- On Day 6, you'll map the system design into an IDL specification. You'll see how system objects map to IDL classes, how partitions map to IDL modules, and other aspects of the interface definition process. You'll also consider various CORBAservices and CORBAfacilities to see how they might fit into your system design. You'll then implement the basic capabilities of the banking application. You'll use the IDL definitions you created as a starting point, from which you'll write separate implementations for the server and client.
- On Day 7, you'll extend the basic capabilities of the application to include exception handling. Exception handling provides error-checking capability, making the application implementation more robust. Changes to the application begin in the IDL code and then propagate through the implementation code.
- On Day 8, the application will gain complexity as you add another CORBA client to the mix: the Automated Teller Machine (ATM) client. CORBA applications usually include more than one client component, so this chapter gives you some exposure to managing multiple clients in a CORBA application.
- On Day 9, you'll wrap up the banking application example with one final enhancement: the capability to "push" update information from the server to the client(s), using client callbacks.
Although object-oriented technologies have existed for quite some time, the phrase "object-oriented" has gained much popularity (along with buzzword status) in recent years. Indeed, the phrase is often bandied about with reckless abandon, which serves to obscure its real meaning. To further confuse matters, it is used to describe everything from development environments to programming languages to databases.
So what does the term object-oriented really mean? The term seems to be thrown about indescriminately; anything from programming languages to drawing tools might be labeled as "object-oriented." For the purposes of this book, you will be interested primarily in three uses of object-oriented methodology: object-oriented analysis (OOA), which deals with the design requirements and overall architecture of a system; object-oriented design (OOD), which translates a system architecture into programming constructs (such as interfaces, classes, and method descriptions); and object-oriented programming (OOP), which implements these programming constructs. So, for your purposes, object-oriented can be taken to mean the various methodologies, described briefly herein, used to design and implement software. This chapter deals primarily with object-oriented analysis. On Day 6 you'll work with object-oriented design; when implementing system functionality, you'll be using object-oriented programming techniques.
Although this book introduces you to object-oriented analysis, design, and programming concepts, it does not attempt to cover these topics in detail. A number of books already written on these subjects provide a definitive introduction to and explanation of these concepts. Time spent familiarizing yourself with these concepts would be time well spent.
The Unified Modeling Language (UML) is a powerful tool for expressing object-oriented designs. Developed by Rational Software Corporation, UML is an evolution of previous modeling languages and techniques. A description of UML, along with a set of links to UML-related resources, appears on Rational's Web site at http://www.rational.com/uml/index.html.
UML is an evolution of previous modeling languages and techniques. Prior to UML, many object-oriented methodologies existed. Of these, the three major methodologies included Grady Booch's Booch 1993 method, Jim Rumbaugh's Object Modeling Technique (OMT) method, and Ivar Jacobson's Object-Oriented Software Engineering (OOSE) method. In October 1994, Booch and Rumbaugh joined forces to unify their methods, resulting in what was called the Unified Method 0.8 in October 1995. Around that time they were joined by Jacobson, merging the OOSE method with Booch and Rumbaugh's work to form UML 0.9 in June 1996. The UML Partners consortium--consisting of companies such as Digital, Hewlett-Packard, IBM, Microsoft, Oracle, Rational, and Unisys--was then formed to refine UML even further, resulting in UML 1.0 in January 1997. The UML 1.0 documents were submitted for standardization to the Object Management Group (OMG)--the organization responsible for the specification of CORBA standards.
The Unified Modeling Language is a highly visual language; in addition to words and text, it also consists (and in fact primarily consists) of graphs and symbols. Perhaps one of the most important diagrams you will encounter in object-oriented analysis and design is the class diagram, which in turn consists of notations for classes, associations, and inheritance (among other things, but these are the three aspects you'll study here).
The Class Diagram
One important element of the Unified Modeling Language (or any modeling language, for that matter) is the class diagram. The class diagram, sometimes called (incorrectly) an object diagram or object model, describes classes and their relationships to other classes in the system. The class diagram specifies only static relationships--how classes are related to each other--and not dynamic relationships, such as when objects are created or invoke services of other objects.
New Term: A class diagram graphically depicts the relationships between classes in a system. Depending on the level of the diagram's scope, it may also describe the attributes and operations provided by each class.
The class diagram is one of the most important elements of an object-oriented methodology. It is essential to the understanding of a complex system architecture and provides a great deal of insight into a system design.
Naturally, the existence of the class diagram implies the existence of the class. As you might expect, the class in UML is analogous to a class in an object-oriented programming language such as Java or C++. A class has a name, zero or more attributes, and zero or more operations. Think of attributes as member data and operations as member functions or methods. In a class diagram, a class description can take on one of the forms shown in Figure 5.1.
Figure 5.1. UML class descriptions.
Figure 5.1 depicts three examples for the representation of a class. In the first example, only the class name is visible. This form is suitable for a class diagram that focuses primarily on the relationships between classes. For example, an extremely complex class diagram benefits from this type of simplification, especially if the diagram is only to be used to provide an overview of an entire system. The second example shows the class name, its attributes, and its operations, but attributes and operations are listed by name only--types and parameters are omitted. The third example shows a fully embellished class description, with class name, attributes and their types, and operations with their parameters and return types. These types of class descriptions are useful when detailed information about a system and its classes is required.
A class description can also provide visibility modifiers for its attributes and operations. The visibility modifier, which is optional, immediately precedes the attribute or operation that it describes. (When no visibility modifier is given, the attribute or method is usually assumed to be public.) A description of each of these modifiers appears in Table 5.1.
Table 5.1 UML Visibility Modifiers.
|+||Public attribute/operation||Public attributes and operations of a class are available to that class and to any other class.|
|#||Protected attribute/operation||Protected attributes and operations of a class are available only to that class and its subclasses.|
|-||Private attribute/operation||Private attributes and operations of a class are available only to that class, excluding even subclasses.|
|/||Derived attribute||A derived attribute is an attribute that is dependent on another attribute. For example, although a person's age can be considered an attribute, it is dependent on the current date and the person's birth date. Derived attributes can also be public, protected, or private.|
|$||Class attribute/operation||A class attribute or operation can be accessed without an instance of the class. Class attributes and operations are analogous to static class members in C++ or Java. Class attributes and operations can also be public, protected, or private.|
A class typically does not exist and act within a vacuum; generally it will interact with other classes as well. Thus, it can be said that a class has relationships to other classes. UML refers to these relationships as associations. A class has an association with another class if it uses services of that class in some way. Optionally, the association can be given a name; additionally, the roles that each class plays in an association can be given names as well. Figure 5.2 illustrates the notation for an association, which is indicated by a line drawn between two classes.
New Term: An association between two classes means that the classes are somehow related. Typically this means that one of the classes uses services of the other or has a member which is an instance of the other class.
An association can also have multiplicity, meaning that a certain number of one class can be associated to a certain number of the other class. For example, Figure 5.2 indicates that a Customer can hold more than one Account. Furthermore, an Account can be held by more than one Customer (as is the case with joint Accounts). Finally, an Account can be owned by only one Bank. Essentially, there are three types of multiplicities in relationships:
- A one-to-one association is an association between exactly one of each type of object.
- A one-to-many (or, conversely, many-to-one) association is an association between exactly one of one type of object and zero or more of the other type.
- A many-to-many association is an association between zero or more of each type of object.
Figure 5.2. UML class associations.
New Term: Multiplicity refers to the number of classes involved in an association. Examples of multiplicity are one-to-one, one-to-many, and many-to-many.
Specifying multiplicity is optional; this information is sometimes omitted for the sake of clarity in high-level class diagrams. However, you need to specify multiplicities of associations before implementing your design, as the details of the implementation depend on this multiplicity information.
Inheritance is actually a special case of an association. It has the same meaning as you would expect in an object-oriented language; a class that inherits from (or derives from) another class (recall from Day 3 that this is referred to as the superclass) inherits the nonprivate attributes and methods of that superclass. Again recalling from Day 3, remember that the derived class can be substituted wherever its base class is required (as a parameter to a method call, for instance); this behavior is known as polymorphism.
In UML, inheritance is represented as an arrow drawn from the derived class to its base class. UML supports the notion of multiple inheritance as well; in this case, arrows are drawn from the derived class to each of its base classes. Examples of UML expressions of inheritance associations are illustrated in Figure 5.3.
Again, it is far beyond the scope of this book to discuss object-oriented analysis and design methodologies in depth. However, a good first step in the analysis phase is to identify the objects, or classes, that compose the system. Many objects in the system are easy to identify; one method is to first write a description of the system and its function. When the description is complete, review it and look for nouns. When you encounter a noun, chances are that it will represent an object in the system. For example, in the sentence "Customers hold accounts in a bank," potential object candidates are Customer, Account, and Bank. This process, sometimes called object discovery, is very useful in understanding the scope of a particular system.
Figure 5.3. UML inheritance associations.
After the candidate objects have been identified, you determine the relationships between the classes. These relationships are often expressed in the form of verbs in the system description. In the preceding example, for instance, you see that Customers hold Accounts, suggesting a relationship between these two classes. Furthermore, you can see that Accounts are part of a Bank, although it is not clear precisely what the relationship is between an Account and a Bank. Associations between classes don't have to be named, although named associations often provide additional insight into the design of a system.
Note:If you infer from this process that classes ought to be named with nouns and associations ought to be named with verbs, you are correct. This naming scheme is a generally accepted convention of object-oriented analysis. Another convention is to give singular names to classes, for example, Account rather than Accounts.
After the classes and their associations have been identified, you'll want to spend some time determining the attributes and operations within classes. This requires more thought than the first two steps, and chances are you won't get it right the first time. In fact, the entire process is an iterative one. While identifying relationships between classes, you might discover new classes, or while determining operations on objects, you might discover new associations or new classes. In fact, your design might change drastically from start to finish; this is a normal aspect of software design. Multiple iterations of this process help you create a robust design, and creating a solid design early on will help you avoid headaches later on in the development phase. (It is often observed that the later in the development process a change needs to be made, the more costly that change will be. Therefore, it is to your advantage to spend a good amount of time refining your design.)
UML is a very broad-reaching tool that encompasses not only the static design of a system (such as the class diagram) but also the dynamic design (including use cases, state transition diagrams, and other tools). Because this book can barely scratch the surface of UML and its functionality as a design tool, you should explore either the Rational Software Corporation Web site (provided at the beginning of this section) or one of several other sources for more information on UML.
The next several chapters center around a single example--an electronic banking system. In this chapter, you'll use object-oriented analysis to define the objects in the system and create an application object model. In subsequent chapters, you'll implement the system's basic functionality and then implement additional capabilities and robustness. In the end, you'll have built a complex (although still trivial by enterprise application standards) CORBA application. Along the way, you'll discover some of the issues involved in building such a system.
The Bank application supports electronic banking. It allows for multiple banks, multiple accounts (checking and savings), multiple customers, opening and closing accounts, and the withdrawal, deposit, and transfer of funds between accounts. (More capabilities are added in later chapters, but the basic Bank application begins with this functionality.)
The first step in designing any system is to determine what the system needs to do. Depending on the nature of the application, this process can involve meeting with customers and/or potential users of the system, conducting market research, or just providing a solution to a particular problem. Requirements often have to be refined or clarified later, so don't be surprised if you find yourself revisiting this step again.
For the Bank example, the capabilities of the basic system are defined as follows:
- Supports multiple banks
- Supports multiple accounts within banks
- Supports multiple customers holding accounts
- Supports customers holding multiple accounts
- Supports the capability to open (create) new accounts
- Supports the capability to close (delete) existing accounts
- Supports the capability to enumerate a bank's accounts
- Supports the capability to determine an account's owner(s)
- Supports the capability to withdraw funds from an account
- Supports the capability to deposit funds into an account
- Supports the capability to transfer funds between accounts within a single bank
- Supports the capability to transfer funds between accounts in different banks
- Supports checking accounts (which don't gain interest)
- Supports savings accounts (which do gain interest)
Notice that each line item describes one capability; for instance, the capabilities to create and delete accounts compose separate line items. This convention facilitates the development of testing requirements because the functionality described in each line item is individually testable. Note also that when analyzing system requirements, it is generally good practice to ensure that each capability is indeed testable. For example, a requirement such as "Must be easy to use" is subjective and so probably not testable. Avoid vague requirements like this; a more useful set of requirements would list specific user-interface features that one might consider "easy to use."
Now that you have arrived at a set of system requirements, you are ready to determine what objects exist in the system. As suggested previously, you do this by scanning the application description and requirements for nouns. Nouns that you'll encounter are bank, account (specifically, checking account and savings account), customer, and funds. All these are candidates for inclusion in the object model (or class diagram). One way to determine whether a class should be created for a candidate is to ask yourself this question: Is there an identity or behavior associated with this object? If the answer is yes, then the candidate should be an object. Try this test on your list of candidate objects:
- Bank: A bank does indeed have identity; the Eighth National Bank is distinguishable from the CORBA Developers Credit Union. Furthermore, a bank has associated behavior; it can open and close accounts on behalf of customers, among other things. Therefore, you might conclude that Bank is indeed an object in your system.
- Account: Accounts, like banks, have identity as well; they can be distinguished from each other. Also, accounts have associated behavior; funds can be deposited in, withdrawn from, and transferred between accounts. Therefore, Account will be an object in the system as well.
- Customer: Customers certainly have identity--John Doe can be distinguished from Joe Blow, the person holding Social Security number 123-45-6789 can be distinguished from the person holding Social Security number 234-56-7890, and so on. Customers don't have any associated behavior, at least for the purposes of this application, but their identity alone suggests that Customer ought to be an object in the system.
- Funds: Funds don't really have identity--one $150.00 amount is, practically speaking, indistinguishable from another $150.00 amount. There is no behavior directly associated with funds either; they can be deposited in, withdrawn from, and transferred between accounts, but this is a behavior of the account rather than the funds themselves. Finally, funds can be easily represented by a simple floating-point value rather than by a class. For these reasons, you probably do not want to include funds in the application's object model.
From this analysis, you can see that the system will include at least three major classes: Bank, Account, and Customer. Now you need to focus your attention on the attributes and behaviors of such objects.
Several of the system requirements suggest behaviors that should be included in the Bank class:
- Supports multiple banks.
- Although not actually a behavior of a Bank, this capability requires that more than one Bank object can exist. Furthermore, in a CORBA application, this requirement suggests that a mechanism exist that can provide clients with visibility to Bank objects. One approach is to require Banks to register with the Naming Service so they can be located by clients; another approach is to create a separate object--BankServer, for instance--that provides visibility to Bank objects. This application uses the latter approach.
Note:In a C++ or Java application that does not use CORBA, you can very well provide a static method of Bank that would return a list of Bank objects, which is a reasonable approach. However, because CORBA objects don't support static methods, an alternative approach--such as those mentioned previously--is required.
- Supports multiple accounts within banks.
- This requirement suggests that a Bank maintain a list of its Accounts, although this list might not necessarily be accessible to objects outside the Bank.
- Supports the capability to open (create) new accounts.
- This requirement suggests that a Bank support an operation such as createAccount(), which presumably will take as input a Customer (or group of Customers) and perhaps an opening balance and will return a new Account object. In other words, Bank will provide the following operation:
- createAccount(customer : Customer, openingBalance : float) : Account
- Supports the capability to close (delete) existing accounts.
- Because an Account must first exist in order to be deleted, this behavior could actually belong either to the Bank class or to the Account class. For the sake of consistency with createAccount(), it is included in the Bank class.
- deleteAccount(), as this operation might be called, doesn't require any information other than the Account to be deleted, so its signature might look like this:
- deleteAccount(account : Account) : void
Note:You will often encounter situations like the preceding one, where there is no clear answer as to where certain behavior should be placed. Use your best judgment, or sometimes even make an arbitrary decision.
- Supports the capability to enumerate a bank's accounts.
- It was suggested previously that a Bank would maintain a list of its Accounts; this requirement suggests that the Bank's Accounts be made accessible to other objects. In a real-world system, access to Account information should probably be restricted, but because there is no such requirement in this system (yet), this operation is straightforward:
- getAccounts() : Account
- The  notation indicates that listAccounts() returns an array of Account objects.
Additional attributes of a Bank might prove useful; for instance, the Bank should probably have a name and perhaps an address. For this application, these attributes will be kept simple:
name : string address : string
BankServer is a class that was unanticipated in the preliminary analysis but popped up during your analysis of the Bank class. The BankServer class is very simple, its only job being to provide visibility to Bank objects. In order to provide this capability, the following operations are required: Register a Bank with the BankServer, unregister a Bank from the BankServer, and list all Banks currently registered with the BankServer. More formally, these operations are defined as follows:
registerBank(bank : Bank) : void unregisterBank(bank : Bank) : void getBanks() : Bank
For the purposes of this application, no other capabilities are required of the BankServer class.
The next class you will consider is the Account. This class implements a great deal of the Bank application's initial functionality. Here is how the Account class meets the requirements of the system design:
- Supports multiple customers holding accounts.
- This capability is supported by a many-to-one relationship between Customers and Accounts, but it also implies that an Account object will support an operation that shows which Customers are associated with that Account:
- getCustomers() : Customer
- Supports customers holding multiple accounts.
- This capability, coupled with the requirement to support multiple customers holding accounts, implies a many-to-many relationship between Customers and Accounts (rather than the many-to-one relationship mentioned previously). However, the actual functionality related to this requirement belongs in the Customer class.
- Supports the capability to determine an account's owner(s).
- This capability implies an operation that returns the Customers associated with a given Account. Incidentally, this operation was already provided previously.
- Supports the capability to withdraw funds from an account.
- The capability to withdraw funds from an Account would most likely come in the form of a withdraw() operation, which takes the amount to be withdrawn as an argument. For the sake of convenience, this operation will return the new balance of the Account:
- withdraw(amount : float) : float
- Supports the capability to deposit funds into an account.
- Depositing funds has the same semantics as withdrawing funds; the amount to be deposited is an argument, and the return value is the new balance of the Account:
- deposit(amount : float) : float
- Supports the capability to transfer funds between accounts within a single bank.
- Transferring funds between Accounts is slightly more complicated than simply depositing or withdrawing funds. In this case, the second Account must also be specified. The amount of the transaction must be specified as well, of course. As with the deposit() and withdraw() operations, the transfer() operation will return the new balance of the Account (meaning the Account from which the funds are transferred):
- transfer(other : Account, amount : float) : float
- Supports the capability to transfer funds between accounts in different banks.
- This capability is already supported by the transfer() operation because the Account passed to that operation can belong to any Bank. Therefore, it is unnecessary to provide a separate operation for transferring funds between Accounts in different Banks.
- Supports checking accounts (which don't gain interest).
- Supports savings accounts (which do gain interest).
These requirements suggest that specializations of the Account class will exist. In particular, you will use CheckingAccount and SavingsAccount. Although one could argue that the account type is actually an attribute of the Account class, for the purposes of this application, the CheckingAccount and SavingsAccount will be subclasses of Account. This approach makes sense because a SavingsAccount has attributes and behaviors not applicable to a CheckingAccount, and vice versa. Because these classes exhibit different behaviors, it is probably better to create separate classes for each of them.
Finally, the Account should probably contain some additional attributes to make it interesting. First, it should have an account number so that it can be identified by a human customer (and also to identify the account on printed checks); it would also be nice to retain the creation date of the account. Note that these capabilities were not spelled out in the requirements, so you could technically do without them. However, they are likely to become useful sooner or later, hence their inclusion here:
accountNumber : string creationDate : date getAccountNumber() : string getCreationDate() : date
Notice that the operations listed here are redundant with the attributes. This is in keeping with the typical practice of making attributes private and allowing access to those attributes through accessor methods. Although you can choose not to follow this convention for non-CORBA applications, access to attributes of CORBA objects always takes place through accessor methods. Remember, though, that one advantage to this convention is that it allows you, if you so desire, to restrict external access to object attributes to reading only. Such is the case in this example, as only accessors--no mutators--are provided. This ensures that attributes that should be immutable--such as creation date and account number--cannot be altered.
CheckingAccount, which derives from Account, provides additional attributes and behaviors. However, at this point in the application design, CheckingAccount adds nothing new to Account.
SavingsAccount, which also derives from Account, provides additional attributes and behaviors as well. In particular, a SavingsAccount has an associated interest rate, along with an accessor and mutator for this attribute:
interestRate : float getInterestRate() : float setInterestRate(newRate : float) : float setInterestRate()
returns the old interest rate as a convenience to the user.
The Customer in this application is a relatively simple class because it is mostly a consumer of services offered by other classes. Only one of the system requirements falls to the Customer class's responsibility.
- Supports customers holding multiple accounts.
- Because a customer can hold multiple accounts, it makes sense that the Customer class would support an operation that enumerates Accounts held by that Customer:
- getAccounts() : Account
Additionally, to make the Customer interesting, a few attributes will be added to provide the Customer's name, Social Security number (as a means of identification), address, and mother's maiden name (for security reasons and just plain old tradition):
name : string socialSecurityNumber : string address : string mothersMaidenName : string
To keep things simple, the address attribute is simplified into a string rather than street address, city, state, ZIP code, and so on. However, providing a separate Address class (which could possibly have derived classes as well) might not be a bad idea for a more robust system.
A Word About Object Identity
Notice that nowhere in the previously described classes is there any mention of attributes whose purpose is to uniquely identify the object. (The possible exceptions are the Customer's Social Security number and the Account's account number, which will be discussed in a moment.) This is because object-oriented analysis makes the assumption that objects implicitly have unique identity, making an identity attribute redundant. Therefore, at the analysis level, classes should not contain attributes that exist solely to identify the object.
There are exceptions to this rule. Most notably, a Customer has a socialSecurityNumber--an attribute that exists primarily to uniquely identify the Customer. However, this type of identity attribute is often used because it corresponds to a real-world concept. A person, for example, has a unique identity simply by virtue of the fact that he or she exists. The Social Security number, because it is a ubiquitous method of identifying people (at least in the U.S.A.), is often convenient to use in software applications.
Other identification attributes exist as well and are perfectly legitimate for use in an application design. Another example is the account number in the Account class. Account numbers are often used to identify an account on a printed check or on a statement sent to the customer.
The key to understanding when identity attributes are appropriate is this: An artificial identity attribute has no place in a class description, whereas an identity attribute that exists in the real world--such as a socialSecurityNumber--is acceptable and even useful.
Now that you've identified the components (classes) of the system and described their attributes and behaviors, you're ready to put them together into a cohesive class diagram. The class diagram shows not only the classes themselves (including, if desired, their attributes or operations) but also the relationships between classes.
Figure 5.4 shows the initial class diagram for the Bank application. (You'll be making changes to the class diagram from time to time as the system design evolves throughout the next few chapters.) Notice that this diagram introduces the UML notation for class inheritance; the SavingsAccount and CheckingAccount classes both inherit from the Account class.
Again, it is stressed that the analysis and design phase is an iterative process. You will often find yourself going back and tweaking various aspects of the design as you discover features that were left out or as you learn (stumble across) a more elegant way of doing things. Revisiting and making changes to work you've already completed is quite normal in this stage of the game. Strive for the highest possible quality system design; when you begin implementing the system, sweeping changes to the design become much more costly. Better to spend more time on it now, during the design phase, when making changes is much cheaper.
Figure 5.4. The Bank application class diagram.
Of course, there is much, much more to object-oriented analysis and design than is covered here. Also, a very important part of object-oriented methodology is the development of use cases, which describe scenarios in which various parts of the system interact. These scenarios contain actors, such as a user or another object, that act on other objects. Use cases describe how an actor interacts with the system, what the results are, and the order in which these events occur. There are many possible use cases for a single scenario; for example, for a given dialog box, there might be a use case for when the user enters valid data and a separate use case for when the user enters invalid data.
Another powerful tool of object-oriented analysis and design is the design pattern. Design patterns can be thought of as building blocks for more complex object-oriented constructs. For instance, one common design pattern--one with which you might already be familiar--is the model-view pattern. In this pattern, one object, called a model, represents a piece of data or concept. Another object, called a view, tells a model that it wants to receive updates whenever the model's state changes. An example of a model class is a TemperatureSensor, which monitors the outdoor temperature. A view class, such as TemperatureDisplay, might be a view of the TemperatureSensor class, meaning that when the TemperatureSensor detects a change in the outdoor temperature, it notifies the TemperatureDisplay of the change. The TemperatureDisplay obtains and displays the new temperature information. A model might have multiple views, as well; in this case, the TemperatureSensor notifies multiple TemperatureDisplays when the outdoor temperature changes.
A number of excellent books have long been available on subjects such as use cases, design patterns, and other important object-oriented concepts. Again, you are encouraged to explore these topics in depth; knowledge of such concepts pay off in designing any type of system--not just CORBA applications.
In this chapter, you took what was essentially a crash course in object-oriented analysis and design. You learned a bit about the Unified Modeling Language, its notation, and the basic methodologies involved. You applied these concepts to the design of a basic Bank application. In the analysis and design phase, not much attention is given to the details of implementation; in fact, it is recommended that you avoid implementation details at this stage of application development. A system design that does not depend on such details enjoys greater flexibility than a design that is dependent on the details of a particular implementation.
In the analysis and design phase, you performed three major steps:
- Investigated and defined the requirements for the system.
- Identified the potential classes that compose the system.
- Mapped the system requirements to class attributes and operations.
- Created a class diagram that integrated the classes in the system into a coherent model.
In the final part of the design phase--on Day 6, "Implementing Basic Application Capabilities"--you'll translate the system design into an IDL specification. The IDL will be used as--you guessed it--a baseline for the system implementation. You'll then proceed to do exactly this--implement the system's basic capabilities. Future days will be spent enhancing the basic functionality.
- Q In the Bank application, what's to prevent someone from transferring funds between accounts without authorization?
A The short answer is this: absolutely nothing. This application, being an oversimplification of a real-world bank system, makes no attempts at providing security of any kind. Obviously, in a production system, there would have to be security measures in place to prevent this sort of thing. (If you're truly ambitious, design such a mechanism as an exercise.)
Q What use are use cases?
A Use cases are a powerful tool in system design; in addition to helping the system architects/designers/developers better understand how the system works, the practice of building use cases can often uncover scenarios that may not have been anticipated. Murphy's Law being what it is, a user will likely uncover all unanticipated scenarios--usually with undesirable results--so it is always better for the application designers to find them first.
The following section will help you test your comprehension of the material presented in this chapter and put what you've learned into practice. You'll find the answers to the quiz and exercise in Appendix A.
- 1. Identify the potential objects in the system described here: An ordering system allows customers to order products from a particular company. Each order consists of one or more line items, each of which identifies a quantity and a particular product. Each product, in turn, has an associated price.
2. What is UML and what is it good for?
3. For an order processing system design, one requirement given is "must be fast." Is this a reasonable expression of this requirement, or could it be made better? If so, how?
Modify the system design so that a Bank consists of Branches, each of which owns some of the Customer Accounts. Draw the class diagram for the modified design.
© Copyright, Macmillan Computer Publishing. All rights reserved.