C H A P T E R  9

Object-Oriented Analysis and Design

A Play in Several Acts

When doing analysis you are trying to understand the problem. To my mind this is not just listing requirements in use cases. … Analysis also involves looking behind the surface requirements to come up with a mental model of what is going on in the problem. … Some kind of conceptual model is a necessary part of software development, and even the most uncontrolled hacker does it.

–-Martin Fowler1

Object-oriented design is, in its simplest form, based on a seemingly elementary idea. Computing systems perform certain actions on certain objects; to obtain flexible and reusable systems, it is better to base the structure of software on the objects than on the actions.

Once you have said this, you have not really provided a definition, but rather posed a set of problems: What precisely is an object? How do you find and describe the objects? How should programs manipulate objects? What are the possible relations between objects? How does one explore the commonalities that may exist between various kinds of objects? How do these ideas relate to classical software engineering concerns such as correctness, ease of use, efficiency?

Answers to these issues rely on an impressive array of techniques for efficiently producing reusable, extendible and reliable software: inheritance, both in its linear (single) and multiple forms; dynamic binding and polymorphism; a new view of types and type checking; genericity; information hiding; use of assertions; programming by contract; safe exception handling.

—Bertrand Meyer2

__________

1 Martin, Robert, Single Responsibility Principle. www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod. Retrieved on December 10, 2009.

PRELUDE: In Which We Set the Scene

When defining object-oriented analysis and design, it's best to keep in mind your objectives. In both of these process phases we're producing a work product that is closer to the code that is your end goal. In analysis, you're refining the feature list you've created and producing a model of what the customer wants. In design you're taking that model and creating the classes that will end up being code.

In analysis you want to end up with a description of what the program is supposed to do, its essential features. This end product takes the form of a conceptual model of the problem domain and its solution. The model is made up of a number of things, including use cases, user stories, preliminary class diagrams, user interface storyboards, and possibly some class interface descriptions.

In design you want to end up with a description of how the program will implement the conceptual model and do what the customer wants. This end product takes the form of an object model of the solution. This model is made up of groups of related class diagrams, their associations and descriptions of how they interact with each other. This includes the programming interface for each class. From here you should be able to get to coding pretty quickly.

ACT ONE, Scene 1: In Which We Enquire into Analysis

So what is object-oriented analysis? Well, it depends on who you talk to. For our purposes, we'll define object-oriented analysis as a method of studying the nature of a problem and determining its essential features and their relations to each other.3 Your objective is to end up with a conceptual model of the problem solution that you can then use to create an object model – your design. This model doesn't take into account any implementation details or any constraints on the target system. It looks at the domain that the problem is in and tries to create a set of features, objects and relations that describe a solution in that domain. What makes a feature essential? Typically, a feature is essential if it's a feature the customer has said they must have, if it's a non-functional requirement that the program won't run without, or if it's a core program element that other parts of the program depend on.

The conceptual model describes what the solution will do and will typically include use cases,4 user stories,5 and UML sequence diagrams.6 It can also include a description of the user interface and a preliminary set of UML class diagrams (but that, of course, is shading over into design).

So how do you create this conceptual model? Just like all the other methodologies in software development there is exactly one correct way to create a conceptual model – not! Really, just like with all the other methodologies we've talked about, the correct answer is: it depends.

__________

2 Meyer, Bertrand. Object-Oriented Software Construction. (Upper Saddle River, NJ: Prentice Hall, 1988).

3 McLaughlin, Brett D., et. al. Head First Object-Oriented Analysis & Design. (Sebastopol, CA: O'Reilly Media, Inc., 2007).

4 Cockburn, A. (2000). Writing Effective Use Cases. (Boston, MA: Addison-Wesley, 2000).

5 Beck, K. Extreme Programming Explained: Embrace Change. (Boston, MA: Addison-Wesley, 2000).

6 Fowler, M.UML Distilled. (Boston, MA: Addison-Wesley, 2000).

It depends on understanding the problem domain, on understanding the feature list you've already come up with, and it depends on understanding how the customer reacts to each of the program iterations they'll see. As we'll see, change is constant.

The key part of object-oriented analysis is the creation of use cases. With use cases you create a walkthrough of a scenario from the user's perspective and that walkthrough gives you an understanding of what the program is supposed to do from the outside. A program of any size will normally have several use cases associated with it. In fact, a single use case may have alternative paths through the scenario. More on this later.

Once you get a few use cases created how do you get to the class diagrams? There are several methods suggested, but we'll just go over one now and save the rest for later. The first method we'll look at is called textual analysis. With textual analysis, you take your uses cases and examine the text for clues about classes in your programs. Remember that the object-oriented paradigm is all about objects and the behavior of those objects, so those are the two things to pluck out of your use cases.

In textual analysis, you pluck potential objects out of the text by picking out the nouns in your use case. Because nouns are things and objects are (usually) things, the nouns stand a good chance of being objects in your program. In terms of behavior, you look at the verbs in the use case. Verbs provide you with action words that describe changes in state or actions that report state. This usually isn't the end, but it gives you your first cut at method names and parameter lists for the methods.

Let's go back to Burt's Bird Buffet and Bath, the B4++. When last we left the B4++ it automatically opened the feeding doors at sunrise and closed them at sunset. The B4++ was a hit and Alice and Bob were thrilled with its performance. Once again the B4 models were flying off the shelves.

Then one day Burt gets a call from Alice. It seems she has an issue. While the B4++ works just fine, Alice has noticed that she's getting unwanted birds at her bird feeder. Recall that Alice is a songbird fanatic and she's thrilled when cardinals, painted buntings, scarlet tanagers, American goldfinches, and tufted titmice show up at the feeder. But she's not so thrilled when grackles, blue jays, and starlings drive away the songbirds and have their own feast. So Alice wants to be able to close the B4++ feeding doors when the bad birds show up and open them again when the songbirds come back. And you're just the guy to do it.

The first obvious question you ask Alice is, “How do you want to open and close the feeding doors?” “Well,” she says, “how about a remote control? That way I can stay inside the house and just open and close the doors when the birds arrive.” And so the game begins again.

Just like last time we can take this sketchy problem statement and try to put together a use case. Our previous use case looked like:

  1. The sensor detects sunlight at a 40% brightness level.
  2. The feeding doors open.
  3. The birds arrive, eat, and drink.
  4. The birds leave.
  5. The sensor detects a decrease in sunlight to a 25% brightness level.
  6. The feeding doors close.

So the first thing we need to decide is whether our new problem is an alternate path in this use case, or whether we need an entirely new use case.

Let's try a new use case. Why? Well, using the remote control doesn't really fit into the sensor use case, does it? The remote can be activated at any time and it requires a user interaction, neither of which fits with our sensor. So let's see what we can come up with for a remote control use case:

  1. Alice hears or sees birds at the bird feeder.
  2. Alice determines that they are not songbirds
  3. Alice presses the remote control button.
  4. The feeding doors close.
  5. The birds give up and fly away.
  6. Alice presses the remote control button.
  7. The feeding doors open again.

Does this cover all the situations? Are there any we've missed? There are two things to think of. First, in step #1 we have “Alice hears or sees birds.” The question is should the “or” matter to us? In this case the answer is no, because Alice is the one deciding and she's the actor in this use case. We can't control the actor; we can only respond to something the actor wants to do and make available options for the actor to exercise. In our case, our program will need to wait for the signal from the remote control and then do the right thing. (Not to get ahead of ourselves, but look at our program now as an event-driven system and the program has to wait (aka listen) for an event before it does something.)

Secondly, what are the steps in the use case that will help us identify new objects? This is where our textual analysis comes in. In our previous version of this application, we've already got BirdFeeder, Sensor, and FeedingDoor objects. These are identified in the use case easily. So what is new now? The only new object here is the remote control. So what does the remote control do? How many buttons does it have? What does the program do when the remote control button(s) is(are) pressed?

In our example, the remote control seems relatively simple. Opening and closing the feeding doors is a toggle operation. The doors open if they are closed, and close if they are open. Those are the only options. So the remote really just needs a single button to implement the toggle function.

So at the end of the day we've got a new use case and a new class for the B4++ program (see Figure 9-1).

images

Figure 9-1. The new RemoteControl class

And that, I think, is all the analysis we need for this version of the program.

This exercise provides us with a couple of guidelines we can use for analysis.

  • First, make simple classes that work together by sending and responding to messages. In our example, the simple classes FeedingDoor and Sensor encapsulate knowledge about the current state of the BirdFeeder and allow us to control the bird feeder with simple messages. This simplicity allows us to easily add a new way of controlling the bird feeder with the RemoteControl class.
  • Second, we say that classes should have one responsibility. Not only are the FeedingDoor and Sensor simple and easy to control, but they each only do one thing. That makes them easier to change later and easier to reuse.

ACT ONE, Scene 2: In Which We Deign to Design

Now what about design? Assuming you've got a conceptual model from your analysis in the form of a few use cases and a few class diagrams, your design should follow from this. In object-oriented design, you now need to firm up the class designs, decide on the methods your classes will contain, determine the relationships between the classes, and figure out how each of the methods will do what it's supposed to do.

In our current example, we've decided on four classes, BirdFeeder, FeedingDoor, Sensor, and RemoteControl. The first three classes we've already developed, so the question here is do we need to change any of these classes in order to integrate the RemoteControl class into the program? Figure 9-2 shows what we've got right now.

images

Figure 9-2. How to integrate the RemoteControl class?

Thinking about it, it seems that nothing in FeedingDoor nor Sensor should have to change. Why?

Well, it's because the BirdFeeder class uses those two classes, and they don't need to use or inherit anything from any other class; they are pretty self sufficient (ya gotta love encapsulation). If you recall, it's the operate() method in the BirdFeeder class that does all the hard work. It has to check the light level from the Sensor and if appropriate, send a signal to the doors to open or close. So it seems that maybe the RemoteControl class will work the same way. So the question for our design is: does the BirdFeeder class also use the RemoteControl class, or does the RemoteControl class stand alone and just wait for an “event” to happen?

Let's take a look at the code for the operate() method again:

  public void operate()
    {
        lightLevel = s1.getLevel();
        
        if (lightLevel > ON_THRESHOLD) {
            Iterator door_iter = doors.iterator();
            while (door_iter.hasNext()) {
                FeedingDoor a = (FeedingDoor) door_iter.next();
                a.open();
            }
        } else if (lightLevel < OFF_THRESHOLD) {
             Iterator door_iter = doors.iterator();
             while (door_iter.hasNext()) {
                FeedingDoor a = (FeedingDoor) door_iter.next();
                a.close();
            }
        }
    }

In this method, we check the light level from the Sensor object and if it's above a certain level (the sun has risen), then we ask the doors to open. It's the doors themselves that check to see if they are already open or not. Regardless, when the open() method returns, each door is open. The same thing happens with the close() method. Regardless of how they start out, when each invocation of close() returns its door is closed. It seems as if this is just the behavior we want from the RemoteControl object, except that instead of a light threshold, it responds to a button press. So the pseudo-code for pressButton() will look like:

pressButton()
        while (there are still doors left to process) do
                if (the door is open) then
                        door.close()
                else
                        door.open()
                end-if
        end-while
end-method.

And from here you can just write the code.

ACT TWO, Scene 1: Change in the Right Direction

A key element of the last two sections is that object-oriented analysis and design are all about change. Analysis is about understanding behavior and anticipation of change, while design is about implementing the model and managing change. In a typical process methodology, analysis and design are iterative. As you begin to create a new program you uncover new requirements; as the user begins to use your prototypes they discover new ideas, things that don't work for them, and new features they hadn't mentioned previously. All of these things require you to go back and re-think what you already know about the problem and what you have designed. In order to avoid what's known as “analysis paralysis” you need to manage this never-ending flow of new ideas and requirements.

There are a number of techniques that can be used to see and deal with change. The first we'll look at is recognizing what might change in your design. So let's look at the B4++ again. Right now, our B4++ will open and close the bird feeder's doors at sunrise and sunset in response to the light levels returned by the sensor. It will also open and close the feeding doors in response to a button push from the remote control. What might change here?

Well, the hardware might change. If the sensor changes that might affect the Sensor class or it might cause your boss to re-think how the Sensor class should work. You might also get new hardware. This is just like the remote control addition we made above. And just like the remote control example new hardware can result in the appearance of new use cases or changes to existing use cases. These changes can consequently ripple down through your class hierarchy.

The requirements might change. Most likely new requirements would crop up. A requirement change can lead to alternate paths through use cases. This implies that behavior will change requirements, which then leads to design changes. Design change happens because requirements change.

By thinking about what things can change in your program and design, you can begin to anticipate change. Anticipating change can lead you to be careful about encapsulation, inheritance, dependencies of one class on another, and so on.

Songbirds Forever

While we're talking about change, let's look back at B4++ again. It's several weeks now since Alice and Bob received delivery of their new and improved B4++ with remote control. Alice loves it. She can watch the birds out her kitchen window and when the grackles swoop in she just hits the remote control button and the doors shut. The grackles leave disappointed and she hits the button again, the doors open. The new version works like a charm and does everything they had asked for.

There's just one little thing....

Alice has discovered that sometimes she has to run errands, or go to the bathroom, or watch her favorite nature show on The Discovery Channel. When she does this, she can't close the door with the remote and the grackles can come and feed to their hearts content, chasing away all the songbirds. Bummer.

So Alice would like yet another small, insignificant change to the B4++; hardly worth mentioning, really. She wants the B4++ to detect the pesky birds and close the doors automatically. How to do this?

I'll wait....

So the new requirement is that “The B4++ must be able to detect the unwanted birds and close the doors automatically.” Is this a complete requirement? It doesn't seem so because it begs the obvious question – when do the doors open again? So it seems we have at least a couple of things to decide.

  1. How does the bird feeder detect the birds?
  2. How do we distinguish between the unwanted birds and the songbirds?
  3. When does the bird feeder open the doors again after they've been closed?

Luckily for us, our sensor supplier, SensorsRUs, has just come out with a programmable audio sensor that will let us identify birdsong. So if we integrate that hardware into the B4++ that takes care of item #1 above. It also turns out that the pesky birds have way different songs from the songbirds we want to attract, so that the audio sensor can be programmed via firmware to distinguish between the different bird species. Whew! So much for issue #2. So what about issue #3, getting the closed doors open again?

It seems as if there are two ways you can get the B4++ to open the doors again. We can have a timer that keeps the doors shut for a specific amount of time and then opens them again. This has the advantage of simplicity, but it's also a pretty stupid bit of programming. Stupid in the sense that the timer program just implements a countdown timer with no information about the context in which it operates. It could easily open the door while there are still a bunch of unwanted birds around. Another way we could implement the bird identifier is to have it only open the door when it hears one of our songbirds. If you reason that the songbirds won't be around if the pesky birds are still there, then the only time you'll hear songbirds singing is if there are no pesky birds around. If that's the case then it's safe to open the feeding doors.

So let's do a use case. Because opening and closing the feeding doors with the song identifier is a lot like using the remote control, let's start with the RemoteControl use case and add to it.

  1. Alice hears or sees birds at the bird feeder.
    a. 1.1 The songbird identifier hears birdsong.
  2. Alice determines that they are not songbirds.
    b. 2.1 The songbird identifier recognizes the song as from an unwanted bird.
  3. Alice presses the remote control button.
    c. 3.1 The songbird identifier sends a message to the feeding doors to close.
  4. The feeding doors close.
  5. The birds give up and fly away.
    d. 5.1 The songbird identifier hears birdsong.
    e. 5.2 The songbird identifier recognizes the song as from a songbird.
  6. Alice presses the remote control button.
    f. 6.1 The songbird identifier sends a message to the feeding doors to open.
  7. The feeding doors open again.

What we've created here is an alternate path in the use case. This use case looks pretty awkward now, because the sub-cases look like they flow from the upper cases when, in fact, one or the other of them should be done. We can rewrite the use case to look like Table 9-1.

Table 9-1. The Song Identifier Use Case and Its Alternate

Main Path Alternate Path
1. Alice hears or sees birds at the bird feeder. 1.1 The songbird identifier hears birdsong.
2. Alice determines that they are not songbirds. 2.1 The songbird identifier recognizes the song as from an unwanted bird.
3. Alice presses the remote control button. 3.1 The songbird identifier sends a message to the feeding doors to close.
4. The feeding doors close.
5. The birds give up and fly away. 5.1 The songbird identifier hears birdsong.
5.2 The songbird identifier recognizes the song as from a songbird.
6. Alice presses the remote control button. 6.1 The songbird identifier sends a message to the feeding doors to open.
7. The feeding doors open again.

These two paths aren't exactly the same. For instance, in the Main Path, Alice sees the birds give up and fly away before she presses the remote control button. In the alternate path, the bird song identifier must wait until it hears birdsong before it can consider opening the feeding doors again. So we could easily make these two different use cases. It depends on you. Use cases are there to illustrate different scenarios in the use of the program so you can represent them in any way you want. If you want to break this use case up into two different ones, feel free. Just be consistent. You're still managing change.

ACT TWO, Scene 2: In Which the Design Will also Change, for the Better

As we've said before, it is difficult to separate analysis and design. The temptation for every programmer, particularly beginning programmers, is to start writing code now. That temptation bleeds over into doing analysis, design, and coding all at once and thinking about all three phases together. Unless your program is just about 10 lines long, this is usually a bad idea. It's nearly always better to abstract out requirements and architectural ideas from your low-level design and coding. Chapters 5 and 6 talked about this separation more.

Separating object-oriented analysis and design is a particularly difficult task. In analysis we are trying to understand the problem and the problem domain from an object-oriented point of view. That means we start thinking about objects and their interactions with each other very early in the process. Even our use cases are littered with loaded object words. Analysis and design are nearly inseparable, when you are “doing analysis” you can't help but “think design” as well. So what should you do when you really want to start thinking about design?

Your design must produce, at minimum, the classes in your system, their public interfaces, and their relationships to other classes, especially base or super classes. If your design methodology produces more than that, ask yourself if all the pieces produced by that methodology have value over the lifetime of the program. If they do not, maintaining them will cost you. Members of development teams tend not to maintain anything that does not contribute to their productivity; this is a fact of life that many design methods don't account for.

All software design problems can be simplified by introducing an extra level of conceptual indirection. This one idea is the basis of abstraction, the primary feature of object-oriented programming. This is why in UML, what we call inheritance in Java is called generalization. The idea is to identify common features in two or more classes and abstract those features out into a higher level, more general class, that the lower level classes then inherit from.

When designing, make your classes as atomic as possible; that is, give each class a single, clear purpose. This is the Single Responsibility Principle that we'll talk more about in the next chapter on design principles.7 If your classes or your system design grows too complicated, break complex classes into simpler ones. The most obvious indicator of this is sheer size: if a class is big, chances are it's doing too much and should be broken up.

You also need to look for and separate things that change from things that stay the same. That is, search for the elements in a program that you might want to change without forcing a redesign, then encapsulate those elements in classes.

All of these guidelines are key to managing the changes in your design. In the end you want a clean, understandable design that is easy to maintain.

ACT THREE, Scene 1: In Which We Do Design

Your goal is to invent and arrange objects in a pleasing fashion. Your application will be divided into neighborhoods where clusters of objects work toward a common goal. Your design will be shaped by the number and quality of abstractions and by how well they complement one another. Composition, form, and focus are everything.

—Rebecca Wirfs-Brock and Alan McKean8

Identifying objects (or object classes) is a difficult part of object-oriented design. There is no ‘magic formula’ for object identification. It relies on the skill, experience and domain knowledge of system designers (that would be you). Object identification is an iterative process. You are not likely to get it right the first time.

You begin finding objects by looking for real-world analogues in your requirements. That gets you started, but it's only the first step. Other objects hide in the abstraction layers of your domain. Where to find these hidden objects? You can look to your own knowledge of the application domain, you can look for operations that crop up in your requirements and in your architectural concepts of the system. You can even look to your own past experience designing other systems.

__________

7 Martin, 2009.

8 Wirfs-Brock, R. and A. McKean. Object Design: Roles Responsibilities, and Collaborations. (Boston, MA, Addison-Wesley, 2003).

Steps to finding candidate objects in your system:

  1. Write a set of use cases describing how the application will work for a number of different scenarios. remember, each use case must have a goal. Remember that a scenario is a path through a use case. If you have use cases with alternate paths as we saw above, your use case may represent several scenarios.
  2. Identify the actors in each use case, the operations they need to perform, and the other things they need to use in performing their actions.
  3. Name and describe each candidate object. Base the identification on tangible things in the application domain (like nouns). Use a behavioral approach and identify objects based on what participates in what behavior (use verbs).
  4. Objects can manifest themselves in a number of ways. They can be
    • External entities that produce or consume information.
    • Things that are part of the information domain (reports, displays, and the like).
    • Occurrences or events that occur within the system.
    • Internal producers (objects that make something).
    • Internal consumers (objects that consume what producers make).
    • Places (remote systems, databases, and so on).
    • Structures (windows, frames).
    • People (well people are objects, right? We have state and behavior, no?)
    • Things that are owned or used by other objects (like bank accounts, or automobile parts).
    • Things that are lists of other objects (like parts lists, any kind of collection, and so on).

8. Organize the candidate objects into groups. Each group represents a cluster of objects that work together to solve a common problem in your application. Each object will have several characteristics:

  • Required information: The object has information that must be remembered so the system can function.
  • Needed services: The object must provide services relating to the system goals.
  • Common attributes: The attributes defined for the object must be common to all instances of the object.
  • Common operations: The operations defined for the object must be common to all instances of the object.

9. Look at the groups you've created and see if they represent good abstractions for objects and that work in the application. Good abstractions will help make your application easier to re-work when you inevitably need to change some feature or relationship in the application.

ACT FOUR, Scene 1: In Which We Philosophize on Abstraction

Let's change tack here and talk about a different example. Alice and Bob (remember them?) have just moved to a new city and they need to transfer their old Second City Bank and Trust bank accounts to First Galactic Bank. Alice and Bob are typically middle class and have several bank accounts they need to transfer: a checking account, a passbook savings account, and an investment account. (Luckily for them, First Galactic also handles investments – shares in Venusian Mining are particularly hot this year.)

Nobody actually opens a “bank account;” they open different types of accounts that each have different characteristics. You can write checks on a checking account, but you can't write checks on a passbook savings account. You can earn interest on a savings account, but you normally don't earn interest on a checking account; you pay a monthly service fee instead. But, all different types of bank accounts have some things in common. All of them use your personal information (name, social security number, address, city, state, ZIP), all of them allow you to deposit money and withdraw money.

So when putting together a program that handles “bank accounts” you may realize that there will be common attributes and behaviors among several classes. Let's look at some classes for a bank account example, shall we?

Since we know that checking accounts, savings accounts, and investment accounts are all different, let's first create three different classes and see what we've got (see Figure 9-3).

images

Figure 9-3. Bank Accounts with a lot in common

Notice that all three classes have a lot in common. One of the things we always try to do, no matter what design or coding techniques we're using is to avoid duplication of design and code. This is what abstraction is all about! If we abstract out all the common elements of these three classes, we can create a new (super) class, BankAccount, that incorporates all of them. The CheckingAcct, SavingsAcct, and InvestmentAcct classes can then inherit from BankAccount.

So here's BankAccount, in Figure 9-4.

images

Figure 9-4. A cleaner BankAccount class

But wait! Is the BankAccount class one that we would want to instantiate? If you look, you'll see that each of the other classes is much more specific than the BankAccount class is. So there isn't enough information in the BankAccount class for us to use. This means we'll always be inheriting from it, but never instantiating it. It's a perfect abstract class. (Note the little bit of UML below – class diagrams of abstract classes put the class name in italics.) See Figure 9-5.

images

Figure 9-5. The BankAccount as an abstract class

Abstract classes are templates for actual concrete classes. They encapsulate shared behavior and define the protocol for all subclasses. The abstract class defines behavior and sets a common state, and then concrete subclasses inherit and implement that behavior. You can't instantiate an abstract class; a new concrete class must be created that extends the abstract class. Whenever you find common behavior in two or more places, you should look to abstract that behavior into a class and then reuse that behavior in the common concrete classes.

Here's what we end up with after abstracting out all the personal data and common behavior into the BankAccount abstract class. Notice one more little bit of UML here – the new UML arrow types – open arrow ends. These open arrows indicate inheritance; so the CheckingAcct class inherits all the attributes and methods from the BankAccount abstract class. UML calls it generalization because the super class generalizes the subclasses. That's why the arrows point up to the super class. See Figure 9-6.

images

Figure 9-6. The concrete account classes inherit from BankAccount

Now let's move on to explain in detail a number of object-oriented design principles that we've just hinted at so far.

Conclusion

In object-oriented analysis and design it's best to keep in mind your objectives. In analysis you're refining the feature list you've created and producing a model of what the customer wants. You want to end up with a description of what the program is supposed to do, its essential features. This creates  a conceptual model of the problem domain and its solution. The model is made up of a number of things, including use cases, user stories, preliminary class diagrams, user interface storyboards, and possibly some class interface descriptions.

In design you're taking that conceptual model and creating the classes that will end up being code. You want to end up with a description of how the program will implement the conceptual model and do what the customer wants. This is an object model of the solution. This model is made up of groups of related class diagrams, their associations and descriptions of how they interact with each other. This includes the programming interface for each class. This design is an abstraction of the class details and code you'll create later. From here you should be able to get to coding pretty quickly.

References

Beck, K. Extreme Programming Explained: Embrace Change. (Boston, MA: Addison-Wesley, 2000).

Cockburn, A. (2000). Writing Effective Use Cases. (Boston, MA: Addison-Wesley, 2000).

Fowler, M.UML Distilled. (Boston, MA: Addison-Wesley, 2000).

McLaughlin, Brett D., et. al. Head First Object-Oriented Analysis & Design. (Sebastopol, CA: O'Reilly Media, Inc., 2007).

Meyer, Bertrand. Object-Oriented Software Construction. (Upper Saddle River, NJ: Prentice Hall, 1988).

Martin, Robert, Single Responsibility Principle. www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod. Retrieved on December 10, 2009.

Wirfs-Brock, R. and A. McKean. Object Design: Roles Responsibilities, and Collaborations. (Boston, MA, Addison-Wesley, 2003).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.135.36