SELecture 4
SELecture 4
Lecture 4
Low-Level
Design
Low-Level Design
Low-level Design
High-level design
paints an application’s structure in broad strokes.
identifies the system’s general environment (hardware, operating system,
network, and so on) and architecture (such as monolithic, client/server,
and service‐oriented).
identifies the system’s major components such as reporting modules,
databases, and top‐level classes.
should sketch out how the pieces of the system will interact.
Low-level design
fills in some of the gaps to provide extra detail that’s necessary before
developers can start writing code.
gives more specific guidance for how the parts of the system will work
and how they will work together.
refines the definitions of the database, the major classes, and the internal
and external interfaces.
In short, High-level design focuses on what. Low-level design
begins to focus on how.
Low-Level Design
As an analogy,
if you were building a highway system,
The high‐level design would determine what cities would be connected
by highways.
The low‐level design would indicate exactly where the highways would
be placed, where the ramps would be, and what elementary schools would
be surrounded by four‐lane traffic circles.
The border between high‐level and low‐level designs is often rather
fuzzy. Typically, after a piece of the system is added to the high‐level
design, team members continue working on that piece to develop its
low‐level design.
Low-Level Design
OO Design
The high‐level design should have identified the major types of classes
that the application will use. Now it’s time to refine that design to identify
the specific classes that program will need. The new classes should include
definitions of the properties, methods, and events they will provide for
the application to use.
In the following we explain how you can define the classes that an
application will use.
Identifying Classes
The high level design tells you that you should identify the main classes that
the application will use, but it doesn’t tell you how to do that. One way to
pick classes is to look for nouns in a description of the application’s
features.
For example, suppose you are writing an application called FreeWheeler
Automatic Driver (FAD) that automatically drives cars. Now consider the
sentence, “The program drives the car to the selected destination.” That
sentence contains three nouns: program, car, and destination.
OO Design
Refinement
Refinement is the process of breaking a parent class into multiple
subclasses to capture some difference between objects in the class.
One danger to refinement is over-refinement, which happens when you
refine a class hierarchy unnecessarily, making too many classes that make
programming more complicated and confusing. People are naturally good
at categorizing objects. It takes only a few seconds of thought to break cars
into the classes shown in Figure 6-1 . The open arrowheads point from child
classes to their parent classes.
There are a couple hundred models of
car on the roads in the United States
alone. You could refine most of those
models with different options such as
different engine sizes, alloy wheels,
and seat warmers.
The resulting hierarchy would
contain many thousands (or millions)
FIGURE 6-1: People are naturally good at
of classes. Obviously, a hierarchy building inheritance hierarchies.
that large wouldn’t be useful.
Building Inheritance Hierarchies
For example,
where there is a behavioral difference, consider transmission type.
To accelerate a car with automatic transmission to freeway speeds, you
simply stomp on the gas pedal until the car is going fast enough.
Bringing a manual transmission car up to speed is much more
complicated, requiring you to use the gas pedal, the clutch, and the gear
shift.
Both kinds of vehicles accelerate, but the details about how they do it
are different.
In object‐oriented terms, the Car class might have an Accelerate method
that makes the car accelerate. The A utomatic and Manual subclasses
would provide different implementations of the Accelerate method that
handle the appropriate details.
Building Inheritance Hierarchies
Figure 6-2 shows a revised inheritance hierarchy.
The first section under a class’s name lists its properties (just Acceleration
in this example). A subclass does not repeat items that it inherits without
modification from its parent class. In this example, the Automatic and
Manual classes inherit the Acceleration property.
The second section below a class’s name shows methods ( Accelerate in
this example). The method is italicized in the Car class to indicate that it is
not implemented there and must be overridden in the child classes.
Is it tall and thin? In general, tall, thin inheritance hierarchies are
more confusing than shorter ones. Tall hierarchies make it hard for
developers to remember which class to use under different
circumstances.
Do you have a huge number of classes? Suppose your car sales
application needs to track make, model, year, color, engine, wheel size,
and motorized cup holders. If you try to use classes to represent every
possible combination, you’ll get a combinatorial explosion and
thousands of classes
Does a class have only a single subclass? If so, then you can
probably remove it and move whatever it was trying to represent into
the subclass.
Low-Level Design
Object Composition
Inheritance is one way you can reuse code. A child class
inherits all of the code defined by its parent class, so you don’t
need to write it again. Another way to reuse code is object
composition, a technique that uses existing classes to build
more complex classes.
For example, suppose you define a Person class that has
FirstName, LastName, Address, and Phone properties. Now you
want to make a Company class that should include information
about a contact person.
You could make the Company class and give the Company class a
new property of type Person called ContactPerson . Now the
Company class gets the benefit of the code defined by the Person
class without the illogic and possible confusion of inheriting
from Person .
Low-Level Design
DATABASE DESIGN
The most popular kind of databases that you can use to build an
application are relational databases. Relational databases are
simple, easy to use, and provide a good set of tools for
searching, combining data from different tables, sorting results,
and otherwise rearranging data.
Like object‐oriented design, database design is too big a topic
to squeeze into a tiny portion here. However, there is room
here to cover a few of the most important concepts of database
design. You can find a book on database design for more
complete information.
In the following we briefly explains what a relational database
is. Then we after that explain the first three forms of database
normalization and why they are important.
Low-Level Design
Relational Databases
Relational Databases
FIGURE 6-4: A table’s records are often called rows and its fields are often called columns.
Low-Level Design
Relational Databases
A relational database stores related data in tables . Each table holds
records that contain pieces of data that are related. Sometimes records
are called tuples to emphasize that they contain a set of related values.
The pieces of data in each record are called fields . Each field has a name
and a data type. All the values in different records for a particular field
have that data type.
Figure 6-4 shows a small Customer table holding five records. The
table’s fields are CustomerId , FirstName , LastName , Street , City ,
State , and Zip. Because the representation shown in Figure 6 -4 lays out
the data in rows and columns, records are often called rows and fields
are often called columns .
FIGURE 6-4: A table’s records are often called rows and its fields are often called columns.
Low-Level Design
Relational Databases
The “relational” part of the term “relational database” comes from
relationships defined between the database’s tables. For example,
consider the Orders table shown in Figure 6-5 . The Customers table’s
CustomerId field and the Orders table’s CustomerId field form a
relationship between the two tables. To find a particular customer’s
orders, you can look up that customer’s CustomerId in the Customers
table in Figure 6-4 , and then find the corresponding Orders records.
FIGURE 6-5: The Customers table’s CustomerId column provides a link to the Orders table’s CustomerID column.
Low-Level Design
Relational Databases
Relational Databases
Building a relational database is easy, but unless you design the database
properly, you may encounter unexpected problems. Those problems may
be that:
Duplicate data can waste space and make updating values slow.
You may be unable to delete one piece of data without also deleting
another unrelated piece of data.
An otherwise unnecessary piece of data may need to exist so that you
can represent some other data.
The database may not allow multiple values when you need them.
The database‐speak euphemism for these kinds of problems is anomalies.
Database normalization is a process of rearranging a database to put it
into a standard (normal) form that prevents these kinds of anomalies.
There are seven levels of database normalization that deal with increasingly
obscure kinds of anomalies. The following sections describe the first three
levels of normalization, which handle the worst kinds of database problems.
Low-Level Design
Another Way
Another way to look at this is to ask yourself whether the record “Sharon
Simmons, Broadsword, Bow” and the rearranged record “Sharon
Simmons, Bow, Broadsword” would have the same meaning. If yes even if
you switch the values of the two fields, then those fields form a repeating
group.
The way to fix this problem
is to pull the repeated data
out into a new table. Use
fields in the original table
to link to the new one.
Figure 6-6 shows the new
design. The Tutorials and
TutorialWeapons tables are
linked by their Time fields.
The table’s primary key is Time+Game. It cannot have two instances of the
same game at the same time (because you don’t have enough equipment or
counselors), so the combination of Time+Game uniquely identifies the rows.
Even though this table is in 1NF, it suffers from the following anomalies:
Update anomalies - If you modify the Duration or MaximumPlayers value in
one row, other rows containing the same game will be out of sync.
Deletion anomalies - Suppose you want to cancel the Middle Earth
Hold’em Poker game at 4:00, so you delete that record. Then you have lost
all the information about that game. You no longer know that it takes 90
minutes and has a maximum of 10 players.
Insertion anomalies - You cannot add information about a new game
without scheduling it for play. For example, suppose Banshee Bingo takes
45 minutes and has a maximum of 30 players. You can’t add that information
to the database without scheduling a game.
The problem with this table is that it’s trying to do too much. It’s trying
to store information about both games (duration and maximum players) and
the schedule.
Second Normal Form
The reason it breaks the 2NF rules is that some non-key fields do not
depend on all the key fields. Recall that this table’s key fields are Time and
Game . A game’s duration and maximum number of players depends only on
the Game and not on the Time. For example, Water Wizzards lasts for 120
minutes whether you play at 1:00, 4:00, or midnight.
To fix this table, move the data that doesn’t depend on the entire key into a new
table. Use the key fields that the data does depend on to link to the original
table. Figure 6-7 shows the new design. Here the ScheduledGames table holds
schedule information and the Games table holds information specific to the
games.
F IGURE 6-7: Moving the data that doesn’t depend on all the table’s key fields puts this table in 2NF.
Low-Level Design
FIGURE 6-8: Moving non-key fields that depend on other non-key fields into a separate table
puts this table in 3NF.
Low-Level Design