Session 11

Going Deeper into an OO program, Part 1

CS 2530
Intermediate Computing

We did not meet today. These lecture notes have two goals. First, they review of our discussion of OO design and close our running design example. Second, they walk you throughan OO program written in Java, reviewing some Java features we have seen and preparing us to discuss some more Java in greater detail beginning next time.

Where Were We?

As we saw in Session 9, designing a system requires:

In object-oriented design, we use objects as the components in our systems. An object is a set of behaviors packaged along with the data they share. OO design focuses on behavior first because:

A list of objects and responsibilities is the beginning of a design, but not the end. We use several tools to design systems and to document the result. Among them are:

We grow a design by working through a set of specific scenarios, or "use cases", that describe how the system should work. The scenarios help us to identify objects, responsibilities, and interactions.

An Example of OO Design

In designing a solution to the Coffee Machine problem, we considered three scenarios:

Our design now looks like this:

... with an object diagram that looks like this:

the object diagram after three scenarios

... with an interaction diagram that looks like this:

the interaction diagram after three scenarios

All is well.

He's Ba-a-a-ack...

People start to buy Starbucks' lattes instead of Arnold's coffees. Arnold decides to fight back. He wants to modify his machine slightly, so that he can create a "drink of the week". He wants to be able to add new drinks and to change prices at any time, to match his competition. He wants to be able to add espresso, cappuccino, hot chocolate, latte, choco-latte, steamed milk, lemon-lime Kool-Aid -- in short, anything that he can mix together in a cup with water.

(The lemon-lime Kool-Aid is for me.)

He add a couple more buttons, a milk steamer and dispenser, and a few more powder dispensers to the hardware configuration.

How do we change our software design?

The Elephant in the Room

This scenario makes obvious that we have neglected perhaps the most obvious object in Arnold's coffee machine world. The very first scenario spoke of it. The second changed it.

The product that the customer buys.

Our design has violates the Principle of Continuity. A small change in the problem -- a new product, or a new price -- requires a big change in the program. That's because the product, and the price associated with it, are not objects in the system. They are attributes of other objects. Changing a product means changing one or more other objects that share responsibility for it. Same for the price.

A change in the product being sold should be a change in the object that is the product. Same for the price.

As soon as we create a product object, other parts of the system become much simpler. A product knows its own price and recipe. The front panel is not a front panel; that's hardware. It is a product selector, from a collection of products in the system's current database. The product can communicate with the dispensers, because the product knows its own recipe. (Actually, the recipe should be an object, too.)

This localizes knowledge of the card swipe to the cash box. We can further guard our users' privacy by having the cash box query the employee database only for the requested amount, not the employee's full available credit.

Our object diagram now looks like this:

the object diagram after recognizing products

... with an object diagram that looks like this:

the interaction diagram after recognizing products

Notice how much "busier" this interaction diagram is than the previous ones. That is a good sign. There are more objects, each with focused responsibility, each contributing an essential part of the system's behavior.

This design is a reasonable model of the world.

With responsibilities evenly distributed, we can distribute control of the system across many objects. This makes the system easier to extend and modify. (You will come to appreciate this more as we see the benefits in future weeks.)

Designs that Accommodate Change

The new design allows Arnold to change configurations easily.

To add a product, Arnold adds a new product to the product register. To change a price or recipe, Arnold changes the entry for a product in the register.

We now have a dynamic object: the product. The product has behavior and thus is not a static value. It rolls through the system sharing its knowledge. Using an object of this sort localizes the state and behavior of a product into one component.

Having a "smart" object of this sort has a powerful benefit: We minimize communication among the other components by passing around one object that bring with it what needs to be known at each moment. The product object helps of decouple the other objects.

We have no mixer. An object with no (software) responsibility is not an object at all. It should not appear as one in the program.

Think about each of these qualities of our final design. Each will reappear as progress through the course, as we see other kinds of object and other ways to partition responsibility. Ultimately, we will learn that discussing the quality of a design is discussing the futures that it supports naturally.

A New OO Program in Java

According to the intuitive description of object-oriented programming we saw in a previous session, a program is a universe of interacting agents. Our first program, the memo pad, consisted of several interacting agents:

We focused our attention on the database. The program included an interface that defines the set of messages that every MemoDatabase object must respond to. The default database shipped with the program uses a Java hashtable to store its memos, and the database you wrote for Homework 1 uses a primitive Java array.

The calculator from Homework 2 consisted of a similar universe of objects, centered on its Accumulator object. Homework 3 does not require a complete program yet it, too, consists of interacting agents: an Auction and a collection of Bids.

We are now reading a second program, BallWorld. It is simpler than the memo pad but embodies all the same OOP ideas. With this program, we dive in deeper. Its simplicity allows us to revisit all the OOP ideas we saw in the memo pad and to visit for the first time other OOP ideas in more detail.

BallWorld creates a window that contains a ball that "bounces" around the window for a few seconds and then terminates.

[... insert screenshot here? ...]

A BallWorld consists of two objects, a Ball and a BallWorldFrame. Let's consider each in turn. Before we do, let's look at another object that plays a part in the program.

The Disk Class

A disk is a round, colored object.

Details to consider:

We'll talk about Java graphics and the details of the paint() method next time.

Some notes to expand upon the bullet list above...

A Disk maintains several pieces of data to help it do its job. Its location is represented by an ordered pair (x,y), and its radius by an integer. The color of the ball is represented by an instance of class Color, a class defined in the standard Java library.

The paint() method uses two operations of the Graphics passed to it: the method to set the current color of renderer, and the method to display a painted oval at a given location.

The Ball Class

A Ball is a Disk that knows how to move itself.

Details to consider:

We'll talk about inheritance in a bit more detail next time, and then in greater detail later in the semester.

Some notes to expand upon the bullet list above...

We will use this Ball class and several variants of it in several programs throughout the course. This makes it somewhat important to define the behavior of a ball in a reusable way.

In addition to the data it inherits from the Disk class, a Ball keeps track of two integers that represent the horizontal and vertical components of its change of location when it moves.

The move() method makes use of a method provided by the Disk class via inheritance.

The BallWorldFrame Class

Details to consider:

It turns out that BallWorldFrame inherits a paint() method from Frame, too. We'll talk more about Java graphics and the details of the paint() method next time.

Some notes to expand upon the bullet list above...

This class is defined as a subclass -- an extension -- of the Java graphics library class named Frame. A BallWorldFrame object displays itself to the screen using other objects from the Java library.

The BallWorld Driver

There is a third file and class: BallWorld. It is the "driver" for our program. If an OO program is a universe of objects, then something must create the first object and send it a message. The sole purpose of this class is to provide a main() method that defines the starting point for the program. As before, main() must be declared

main() must also take a single argument: an array of Java Strings. Up until now, our programs have ignored this argument. We will see soon how to use the argument to parameterize our application.

It is possible to invoke main() to start the program because it is declared as static. This means that it exists before any instances of its class exist. That is, we do not have to cfreate an instance of class BallWorld in order to invoke this method.

For our simple application, main() simply creates a BallWorld object and tells it to make itself visible. The result must somehow involve the window paint()ing itself to screen... We'll talk about Java graphics next time, and the details of the setVisible() method soon.

Wrap Up

Eugene Wallingford ..... ..... September 24, 2012