You are on page 1of 17

Fundamentals of Program Design

Every computer program is built from components, data, and control.

For a single-user application (used by one person at a time), which


normally reads data, saves it in a data structure, computes on the data, and writes the
results, there is a standard way of organizing the component structure, data structure, and
control structure:

1. First, design the program's component structure with three components, organized
in a model-view-controller pattern.
2. Next, decide what form of data structure (array, table, set, list, tree, etc.) will hold
the program's data. The data structure will be inserted in the
program's model component.
3. Then, write the algorithm that defines the execution steps --- the control structure.
The algorithm will be placed inside the program's controller.
4. Determine the form of input and output (disk file, typed text in a command window,
dialogs, a graphical-use interface, etc.) that the program uses. This will be embedded
in the program'sview.

Once the four-step design is finished, then it is time to convert the design into
(Java) coding.

We now consider each stage of the design process.

Component structure

Again, the program's job is to read information into the computer and save it in a
format which lets the computer compute answers from the data that can
be written.

The program can be written as one large piece of code, but this forces a programmer to
think about all parts of the program at once. Years of experience has shown that it is better
to design a program in three parts, in a model-view-controller pattern:
The data flows into the program through the view component and is directed by
the controller into the model. The controller component manipulates the data and
tells the view to output the answer. A bit more precisely, we have that

 The controller component holds the algorithm, that is the instructions that tell the
computer when to read data, compute on it, and write the answers.
 The model component holds the structures that save the data so that it can be easily
computed upon. For example, if the program is a spreadsheet program, then the
model holds a table (grid) that represents (``models'') the spreadsheet. Or, if the
program is the file manager for Linux, then the model is a tree structure that
represents the folder-and-file structure of the disk-file system.
 The view component holds the operations that connect the program to the input
and output devices (the disk or display or printer....).

All three components are important, but the key to building a good quality
program is selecting the appropriate data structure for the model component.

Data structure

When you solve a problem with a computer program, always ask first,

How should the program store the information upon which it computes?

Sometimes people talk about ``modelling'' the problem within the computer; the way the
data is held is called the model. Recall the previous examples:

 If the program is a spreadsheet program, then the information should be held in a


data structure that is a grid.
 If the program is a bank-account database, then the information should be grouped
into customer accounts, each with a unique ID, saved in an array or set.
 If the program is a file-system manager, then the information are files and folders
that are organized in a tree-like structure.
Each of these problems required a distinct data structure in the solution.

It helps to draw a picture of the structure. For example, if you are writing a vote-counting
program for the 2004 US presidential election, you might draw this picture of the model:

On the other hand, if you are writing the file-system manager for Linux, then
your program must hold folders and files, and the picture of the model might
look like this:

The picture should suggest to you the kind of computer variables and data
structures you will require to build the solution. The purpose of a data-structures
course like CIS300 is to train you at using a variety of such structures.

The model component is ``passive'' --- another program component, the controller, inserts
data into the structure, asks for computations, and extracts the answers.
Control structure

Every program follows a series of steps to solve a problem. The series of steps is
called an algorithm; it controls the computer's work.

It is best to begin with an ``outline'' of the algorithm. The outline can be written in a
graphical form, called a flowchart.

For example, here is an outline, written as a flowchart, of an algorithm for reading and
totalling the votes of the presidential election:

Many people like to develop their algorithms with a flowchart, because the
various paths can be developed one at a time, and the arrows make it less likely
to forget a case in the development.

The algorithm is inserted into the controller component, and when writing the program in
Java, you can code the algorithm into the main method.

Methods for the components


Often we see phrases in the algorithm that are not at the level of Java
instructions. (Examples: ``add one to Kerry's count''; ``print the totals in the
model.'') These phrases are clues that you should write procedures (methods)
that do the work described by the phrases. For example, since the phrase, ``add
one to Kerry's count'' implicitly mentions the data structure in the model, we
might revise our our description of the model component to have a method that
does what the phrase suggests:

This makes the algorithm in the controller easier to write, because it merely
invokes the model's method, meaning that the controller does not have to deal
with the details of the data structure. (This arrangement is also important if we
must change the data structure within the model: the codings of the methods in
the model are changed, and we do not rewrite the controller.)

Later, we write the code for the methods. If the coding is complicated, we might wish to
write flow charts, possibly defining even more methods.

Input and output

A program that reads and writes data will normally use a prebuilt component.
For example, when a program prints output to the command window, it uses
the System.out component and its methods, print and println. For input, if we use
the JOptionPane object from javax.swing to generate an input dialog, then the
application we design would look like this:
Finally, in some cases, the programmer will build a customized input-output
component that uses frames, text fields, buttons, etc. This makes the View
component more complex still. In the next lectures, we design and build
applications using this design process.

Software Development Methodology

The design stage is only one stage in the stages one undertakes to build and
deliver a software application. A standard development methodology goes in
three stages:

1. Requirements: The program's intended user tells us how she wishes to use the
program. The user must tell us stories and draw pictures that explain the different
ways the program might be used. Each possible usage is called a use-case. (Use-cases
are presented in the next lecture.)
2. Design: The programmer studies the use-cases and applies the knowledge to
designing the component structure, data structure, and control structure of the
solution, as described above. Once the program is designed, the programmer does a
``safety check,'' explaining how each use-case executes with the design.
3. Implementation and Testing: The program is written to match the design, and it is
tested to verify that it behaves correctly. The testing usually proceeds in two
stages: unit testing, where each component is tested by itself as much as possible,
and integration testing, where the entire assembled program is tested on the use-
caes.

At this point, the program is given to the user, who will almost certainly respond
with more requirements that cause the above three-step process to repeat.

We apply the software development methodology in the next lecture.

Software development in Java: classes, objects, and packages


In the previous lecture, we learned that programs are designed with three
components: model and view and controller.

The Java language is a bit confusing, because there are two notions for ``component'' --
- class and object. Here is a simplistic explanation:

1. The program pieces we write are classes. Each class lives in a file on disk.
2. When we start a program, copies of the classes are created in the computer's
primary storage. The copy in storage is an object. It is possible to copy a class into
primary storage more than once, thus constructing multiple objects from the same
class. (Example: You write a class LibraryBook, and then you start a program that
constructs 100 new LibraryBook(...)objects.)
3. When we start a program, say
4. java LibraryManager

this constructs a LibraryManager object from class LibraryManager.


Within LibraryManager, there might be statements of the form,

... new LibraryBook(...) ...

The new statement constructs in storage a LibraryBook object from class


LibraryBook. In this way, multiple objects are constructed and live in primary
storage.

5. Before a program starts, there already exist several prebuilt objects, such
as System.in and System.out. A program can use these, say, as the view
component(s) of the application.

To summarize: classes are the components that the programmer writes and saves on disk;
objects are the components that live in primary storage when the program executes. If we
wish to be pedantic, we say that the component diagrams in the previous lecture are object
diagrams.

Software development in Java

Recall the software development methodology stated at the end of the previous
lecture:

1. Requirements: The program's intended user tells us how she wishes to use the
program. The user must tell us stories and draw pictures that explain the different
ways the program might be used. Each possible usage is called a use-case.
2. Design: The programmer studies the use-cases and applies the knowledge to
designing the component structure, data structure, and control structure of the
solution. Once the program is designed, the programmer does a ``safety check,''
explaining how each use-case executes with the design.
3. Implementation and Testing: The program is written to match the design, and it is
tested to verify that it behaves correctly. The testing usually proceeds in two
stages: unit testing, where each component is tested by itself as much as possible,
and integration testing, where the entire assembled program is tested on the use-
caes.

Let's study a simple example.

Case Study: Counting votes

You are the Diebold Company, and the state of Ohio has asked you to write the software for
their electronic voting machines for the 2004 US presidential election.

I. Requirements

You begin by asking the Ohio election officials to give you examples --- use-cases --
- that describe how the software should behave. They might give three such use-
cases:

 ``The voter sees an input dialog on the screen; if the voter votes for Kerry, she
types Kerry and pushes the dialog's OK button. The program remembers the vote.''
 ``If the votes wishes to vote for Bush, the voter types Bush instead.
 ``When all the voters are finished, the election official sees the input dialog, presses
the Cancel button, and the program prints the vote totals on the display.''

The set of use-cases is almost always incomplete, and the program designer might propose
more of them, e.g., ``What happens if the voter types kerry or kery instead of Kerry''?
Rarely does a programmer begin with ``all'' the use-cases, but there should be enough of
them to gain a good understanding of the problem.
II. Design

We now apply the design stages described in the previous lecture.

Component structure

The vote-counting program fits the usual model-view-controller structure:

The first and most important task is to decide the data structure that resides in
the model.

Data structure

The program's job is to total votes, so a table (array) is needed, where each cell of
the array holds the total for one candidate. Here is a picture:

The programmer might ask: ``Are these all the candidates?'' ``Does Ohio allow
write-in ballots?'' The answers to these questions affect the data structure. For
now, we work with the 3-celled array.

Control structure

The controller holds the algorithm that controls vote counting. Simply stated, the
algorithm goes
1. read and total the votes
2. print the totals
We also know that Step 1 must be conducted one vote at a time, so the details for
Step 1 go something like this:
1a. read a vote (if there is one to read! if not, quit Step 1)
1b. if the vote is for Bush (or Kerry or Nader), add one to the appropriate
count
1c. repeat Steps 1a and 1b until no more votes to read
The outline should list all the actions the program must do, even if we do not
state the details precisely. Now we are ready to draw the algorithm as a flow
chart, which is a graph that shows the details and ordering. Here is the flow chart
for Steps 1a and 1b:

Now, we finish the flow chart by including Steps 1c and 2. This adds a loop --- a
backwards arc --- to the flowchart and gives us the following:
When we take a close look at the algorithm, we notice that the phrase, ``get
input,'' which suggests that we should use a method in the view component to
read the vote. Next, the phrase, ''add one to Bush's count,'' suggests we should
make a method in the model component to add a vote for Bush (similarly for
Kerry and for Nader). Finally, the phrase, ``print the totals'', suggests there
should be a method that gets the totals (and a method in the output view to print
them).

This suggests we modify the model with some extra methods:


Input-output structure

Whenever possible, we should use pre-built components to handle input and


output. Since the votes will arrive from an input dialog, we can use the dialog
object that is prebuilt into the Java libraries --- It is javax.swing.JOptionPane. The
output can be printed into a command window, using the object, System.out.

Summary of design

Here is the current picture of our design:


The red dashed arrows are added to remind us which steps in the controller's
algorithm will invoke the methods in the model and the view. The purple solid
arrows are traditional; they summarize the red dashed arrows by telling us
which components depend on the other components to execute. (Here, the
controller cannot execute without its model and view, but the model can be
extracted and used without the controller and view, say, in another application.)

Now it is time to write the codings of the methods and the coding of the algorithm.

III. Implementation

It is best to code the model first, because any flaws in the program's data structures will
render the program useless. Based on our design, here is a coding of the model:

package Election2004;
/** VoteTable remembers the votes for the 2004 US Presidential Election */
public class VoteTable
{
private int[] vote; // holds the votes for the candidates
// vote[0] holds Bush's votes
// vote[1] holds Kerry's votes
// vote[2] holds Nader's votes

/** Constructor VoteTable initializes the table */


public VoteTable()
{ vote = new int[3]; } // all cells are automatically set to 0

/** voteForBush adds one more vote to Bush's total */


public void voteForBush()
{ vote[0] = vote[0] + 1; }

/** voteForKerry adds one more vote to Kerry's total */


public void voteForKerry()
{ vote[1] = vote[1] + 1; }

/** voteForNader adds one more vote to Nader's total */


public void voteForNader()
{ vote[2] = vote[2] + 1; }

/** computeTotals reports the votes for the three candidates


* @return a string that lists the candidates and their votes. */
public String computeTotals()
{ return "Bush = " + vote[0] + "\n"
+ "Kerry = " + vote[1] + "\n"
+ "Nader= " + vote[2] + "\n" ; }
}
This component should be tested by itself (called unit testing) as thoroughly as
possible. You can use a Development Environment (e.g., BlueJ or Eclipse) to do
this, or you can write a tester program, sometimes called a test harness, to do this.
Here is a sample test harness:
package Election2004;
public class TestModel
{ public static void main(String[] a)
{ VoteTable t = new VoteTable();

System.out.println(t.computeTotals()); // all candidates should have 0s

t.voteForNader();
System.out.println(t.computeTotals()); // Nader should have 1

t.voteForKerry();
System.out.println(t.computeTotals()); // Nader and Kerry should have 1

// etc.
}
}
A test harness should test all the methods of the component, invoked in all
possible orderings.

Next, here is the controller, named Start:

package Election2004;
import javax.swing.*;
/** Start starts and controls the vote counting. */
public class Start
{ public static void main(String[] a)
{
VoteTable table = new VoteTable(); // construct model object

// tabulate the votes:


boolean processing = true;
while ( processing )
{ String s = JOptionPane.showInputDialog(
"Please type the last name of your candidate:");
if ( s == null ) // did election official press Cancel ?
{ processing = false; } // yes, time to quit
else { if ( s.equals("Bush") )
{ table.voteForBush(); }
else if ( s.equals("Kerry") )
{ table.voteForKerry(); }
else if ( s.equals("Nader") )
{ table.voteForNader(); }
else { } // it's an invalid vote and is lost forever...
}
}
// total the votes:
System.out.println( table.computeTotals() );
System.exit(0); // terminate program (including graphics components)
}
}
It is a bit difficult to do unit testing on a controller, since it controls the other
parts of the program, but it is possible to write a dummy version of VoteTable for
testing the controller. The dummy version, called a stub (sorry --- it's a bad
name), might look like this:
package Election2004;
/** This is a dummy VoteTable, for testing purposes only. */
public class VoteTable
{ public VoteTable() { }

public void voteForBush() { System.out.println("B"); }


public void voteForKerry() { System.out.println("K"); }
public void voteForNader() { System.out.println("N"); }

public String computeTotals()


{ return "request to compute totals" }
}
There is no intelligence in the dummy version; it is built to let us see the order in
which the controller uses the methods in the model.

Finally, note that we have used the prebuilt objects, javax.swing.JOptionPane (for dialog
input) and System.out (for output to the command window), so there is no additional
programming needed for the view components.

Now, the application is ready for systems testing and ultimately, to let the voters of Ohio
decide the 2004 US presidential election.
Java Packages

Perhaps you notice that the two components in the case study were prefixed by the line,

package Election2004;
This tells the Java compiler that the two classes ``belong together'', and indeed,
they must be placed in the same disk folder (directory), named Election2004. Such
a folder is called a Javapackage.

Java makes it easy to create and execute a package.

(Note: If you use the BlueJ IDE, you should read the CIS300 web pages, Constructing packages
within BlueJ and How to use BlueJ to start a main method to learn how BlueJ lets you build
and execute packages. The notes there might be a bit out of date, but if you are having
problems making packages with BlueJ, the notes might be useful.)

The following instructions work with the Java Development Kit and a command window:
Say that we want to group the above two classes into a package named Election2004:

1. We create a new folder, named Election2004.


2. We insert class Start and class VoteTable into the folder.
3. As the first line of both of the two classes, we insert:
4. package Election2004;
We must recompile the classes:

1. Close (exit) folder Election2004.


2. Compile each class, e.g.,
3. javac Election2004\VoteTable.java

(or, if that doesn't work, use)

javac -classpath . Election2004\VoteTable.java

(The -classpath . tells the Java compiler that the other classes in the package are
found where VoteTable.java lives. ) Note the folder name prefixed to the class
name.

We execute the start-up class of the package in a similar way:


java Election2004.Start
Note that the folder name is prefixed with a dot to the start-up class name.

We can generate an interlinked collection of web pages for the package with just
one javadoc command:

javadoc Election2004
You can see the Election2004 package
at http://www.cis.ksu.edu/~schmidt/300s05/Lectures/VoteExample .

As an exercise, you should copy the two classes to your computer, make a package, compile
it, execute it, and use javadoc to generate its API specification.

There are several advantages to grouping programs into packages:

1. Program components that work together are grouped together --- we won't lose or
forget a component.
2. Packages can be saved in ``libaries'' and reused. Indeed, all the graphics we do with
Java programs reuses packages others wrote for us.
3. The javadoc program can be used to generate a family of cross-indexed web pages
that document all the components in a package. The use of javadoc makes it
possible to quickly document and redocument systems during design and
development.

All three items listed above are important. We have already exploited Item 2 each
time we wrote a program using a graphical user interface --- when we added
import javax.swing.*;
at the beginning of the classes we wrote, we were connecting to and using a
package, namely javax.swing, that someone else wrote.

Indeed, the general pattern for using an already written package, P, in an application is to

 Ensure that the package (folder) P is on our computer.


 Append to the top of each new component that uses the package, the statement,
 import P.*;
This makes the components in the package available for use.

You might also like