0% found this document useful (0 votes)
13 views17 pages

Chapter 15

Uploaded by

sl4429056
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views17 pages

Chapter 15

Uploaded by

sl4429056
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 17

Chapter 15

Class Design

Class design involves the following steps.


■ Bridge the gap from high-level requirements to low-level services.
■ Realize use cases with operations.
■ Formulate an algorithm for each operation.
■ Recurse downward to design operations that support higher-level operations.
■ Refactor the model for a cleaner design.
■ Optimize access paths to data.
■ Reify behavior that must be manipulated.
■ Adjust class structure to increase inheritance.
■ Organize classes and associations.
Bridging the Gap
Realizing Use Cases

• Use cases define the required behavior, but they do not define its realization. i.e the
purpose of design—to choose among the options and prepare for implementation.

• Use cases define system-level behavior. During design you must invent new operations
and new objects that provide this behavior.

• List the responsibilities of a use case or operation. A responsibility is something that an


object knows or something it must do.

• Each operation will have various responsibilities. Some of these may be shared by
other operations, and others may be reused in the future.
Designing Algorithms

Now formulate an algorithm for each operation. The analysis specification tells what
the operation does for its clients, but the algorithm shows how it is done. Perform the
following steps to design algorithms.

• Choose algorithms that minimize the cost of implementing operations.


• Select data structures appropriate to the algorithms.
• Define new internal classes and operations as necessary.
• Assign operations to appropriate classes.
Choose algorithms that minimize the cost of implementing operations. (Choosing Algorithms )

• Many operations are straightforward because they simply traverse the class model to
retrieve or change attributes or links. The OCL provides a convenient notation for
expressing such traversals.
• However, a class-model traversal cannot fully express some operations. We often use
pseudocode to handle these situations. Pseudocode helps us think about the algorithm
while deferring programming details.
• Typically, 20% of the operations consume 80% of execution time. For the remaining
operations, it is better to have a design that is simple, understandable, and easy to
program than to wring out minor improvements.

Here are some considerations for choosing among alternative algorithms.


1. Computational complexity
2. Ease of implementation and understandability
3. Flexibility
Choosing Data Structures

• Algorithms require data structures on which to work. During analysis, you focused on
the logical structure of system information, but during design you must devise data
structures that will permit efficient algorithms.

• The data structures do not add information to the analysis model, but they organize it
in a form convenient for algorithms.

• Many of these data structures are instances of container classes. Such data structures
include arrays, lists, queues, stacks, sets, bags, dictionaries, trees, and many variations,
such as priority queues and binary trees.
Defining Internal Classes and Operations

• You may need to invent new, low-level operations during the decomposition of high-
level operations.

• Usually you will need to add new internal operations as you expand high-level
operations.

• The expansion of algorithms may lead you to create new classes of objects to hold
intermediate results.
Assigning Operations to Appropriate Classes

• When a class is meaningful in the real world, the operations on it are usually clear.
• During design, however, you introduce internal classes that do not correspond to real-
world.
• Since the internal classes are invented, they are somewhat arbitrary, and their boundaries
are more a matter of convenience than of logical necessity.
• During assigning operation you must decide which object plays the lead role in the
operation. Hence ask yourself the following questions:
1. Receiver of action.
2. Query vs. update.
3. Focal class.
4. Analogy to real world.
Recursing Downward
The design process generally works top down—you start with the higher-level operations
and proceed to define lower-level operations. Downward recursion proceeds in two main
ways: by functionality and by mechanism.

Functionality Layers
Functionality recursion means that you take the required high-level functionality and break it
into lesser operations. This is a natural way to proceed, but you can get into trouble if you
perform the decomposition arbitrarily and the pieces do not relate well to classes. To avoid
this, make sure you combine similar operations and attach the operations to classes.

Mechanism Layers
Mechanism recursion means that you build the system out of layers of needed support
mechanisms. In providing functionality, you need various mechanisms to store information,
sequence control, coordinate objects, transmit information, perform computations, and
provide other kinds of computing infrastructure. These mechanisms don’t show up explicitly
in the high-level responsibilities of a system, but they are needed to make it all work.
Refactoring

• The initial design of a set of operations will contain inconsistencies, redundancies, and
inefficiencies. This is natural, because it is impossible to get a large design correct in
one pass.

• It is good to use an operation or class for multiple purposes. But it is inevitable that an
operation or class conceived for one purpose will not fully fit additional purposes. You
must revisit your design and rework the classes and operations so that they cleanly
satisfy all their uses and are conceptually sound.

• Martin Fowler defines refactoring as changes to the internal structure of software to


improve its design without altering its external functionality.
Design Optimization

• A good way to design a system is to first get the logic correct and then optimize it. That is
because it is difficult to optimize a design at the same time as you create it.

• The design model builds on the analysis model. The analysis model captures the logic of a
system, while the design model adds development details. You can optimize the inefficient
but semantically correct analysis model to improve performance.
• Design optimization involves the following tasks.
1. Provide efficient access paths.
2. Rearrange the computation for greater efficiency.
3. Save intermediate results to avoid recomputation.
Adding Redundant Associations for Efficient Access (Provide efficient access paths.)

• Redundant associations are undesirable during analysis because they do not add
information. Design, however, has different motivations and focuses on the viability of a
model for implementation.
• Can the associations be rearranged to optimize critical aspects of the system? Should new
associations be added? Can existing associations be omitted?
• Figure shows a portion of the analysis class model. The operation Company.findSkill()
returns a set of persons in the company with a given skill. For example, an application
might need all the employees who speak Japanese.
• The derived association SpeaksLanguage from Company to Person, where the qualifier
is the language spoken. The derived association does not add any information but
permits fast access to employees who speak a particular language.
• Start by examining each operation and see what associations it must traverse to obtain
its information. Next, for each operation, note the following.
 Frequency of access.
 Fan-out.
 Selectivity.
Rearranging Execution Order for Efficiency (Rearrange the computation for greater efficiency)

• After adjusting the structure of the class model to optimize frequent traversals, the next
thing to optimize is the algorithm itself. One key to algorithm optimization is to
eliminate dead paths as early as possible.

• For example, suppose an application must find all employees who speak both Japanese
and French. Suppose 5 employees speak Japanese and 100 speak French; it is better to
test and find the Japanese speakers first, then test if they speak French.
Saving Derived Values to Avoid Recomputation (Save intermediate results to avoid recomputation)

Sometimes it is helpful to define new classes to cache derived attributes and avoid
recomputation. You must update the cache if any of the objects on which it depends are
changed. There are three ways to handle updates.

Explicit update. The designer inserts code into the update operation of source attributes to
explicitly update the derived attributes that depend on it.

Periodic recomputation. Applications often update values in bunches. You could recompute
all the derived attributes periodically, instead of after each source change. Periodic
recomputation is simpler than explicit update and less prone to bugs.

Active values. An active value is a value that is automatically kept consistent with its source
values. A special registration mechanism records the dependency of derived attributes on
source attributes. The mechanism monitors the values of source attributes and updates the
values of the derived attributes whenever there is a change.

You might also like