Session 20

Interchangeable Objects

CS 2530
Intermediate Computing

Opening Exercise

Write a Java class ButtonDemoFrame to create this window.

border layout manager demo

Whenever the user presses a button, the program writes the name of the button to the standard output.

Toward a Solution

We encounter several design questions in writing this program:

Here is a quick solution: DemoButtonListener and ButtonDemoFrame.

Creating and setting up the five buttons repeats a lot of code. Not much differs among the five button creation snippets.

Can we make the duplication go away?

Sure: we can extract a method that makes buttons: ButtonDemoFrame.

We still have to make five calls to makeButton() when creating the five buttons. That sounds like a job for a loop.

Can we make the duplication go away?

Sure: use an array to map button names and locations to buttons: ButtonDemoFrame.

Look for opportunities to remove duplication, in all its forms.

A MultiBallWorld Symphony, in Five Parts

Here is a MultiBallWorld using a Panel.

Here are two MultiBallWorlds using Panels.

How about nine MultiBallWorlds? Sure.

Here are eight MultiBallWorlds and a button. A Panel can hold other kinds of Component!

Even another Panel. Nice.

What does this tell us about the Java AWT? About programming?

The Composite Design Pattern

For the last few sessions, we have been adding active components such as Buttons and Sliders to our Frames. In the MultiBallWorld symphony. added a Buttons to our Panel, too. Do you think that the AWT duplicates the code for this functionality? It does not. Frame and Panel are both subclasses of Container. These two kinds of object respond to the same messages, because they extend the same superclass. This is a benefit of inheritance.

But it got even better. A Panel can hold other Panels, too! When we add components to a Panel, whether the component is a Button or another Panel, the containing Panel must keep track of these different kinds of objects using the same variables and must send them all the same messages, such as paint(). Each component responds by painting itself. The Button paints itself in the familiar way. A Panel paints itself by sending paint() messages to any components it contains.

This all works because

Finally, a Panel can also contain other Components, including Panels.

a panel is a composite of other components

Buttons, Sliders, Panels, and Frames are all Components, which means they can be used interchangeably by any piece of code that uses Components.

The design of the Component class hierarchy is an example of the Composite design pattern.

... problem. ... forces. ... solution.

This pattern is not specific to Panels, the AWT, Java, or even object-oriented programming. Composites in occur throughout Java, in non-OO programs -- and even the "real world". Some other examples of the composite pattern are:

The fact that composites occur not only in code but also in the real world should not surprise us. Our programs tend to follow the Principle of Continuity, and we learn from how the world works and apply that knowledge in our programs.

Java's AWT

Java's Abstract Window Toolkit, or AWT, uses these ideas all over the place. That means the AWT gives us lots of examples of the composite pattern and interchangeable objects, as do the rest of Java's libraries.

The AWT is a framework, a set of classes that provide objects and control for building graphical applications. It provides built-in control that works in your applications by taking advantage of interchangeable objects through inheritance and interfaces.

Consider a typical message sequence in one of our ...BallWorld programs:

tracing a message through the inheritance hierarchy

The show() message example exemplifies the Hollywood Principle:

Don't call us; we'll call you.

The AWT uses interchangeable objects to allow programmers to create complex applications with as little work as possible, overriding only those methods that need special behavior.

Methods in a framework that you must override are sometimes called hot spots. They are the key to learning and using a new framework. As such, they should also be the focus of documentation for a framework.

Working with a framework introduces some new problems for us to watch for...

The paint() message in the same example also masks the tooth fairy problem, which we face when the framework requires us to override a method in order to see the behavior we expect.

Dealing with the tooth fairy problem is mostly a matter of good documentation and asking questions when you encounter unexpected behavior -- or, more likely non-behavior.

The show() method is an example of the yo-yo problem, which we face when the methods in a framework reside throughout the class hierarchy.

Dealing with the yo-yo problem is mostly a matter of practice. Once you've learned a framework or two, bouncing up and down the class hierarchy will seem natural. (Practice, practice, practice.)

Wrap Up


From its roots, polymorphism means "many shapes" or "many forms". In computing, we use this term to refer to code that works with values of different types. A function or method that can receive arguments of different types is a polymorphic function. A variable that can hold values of different types is a polymorphic variable.

Some languages support pure polymorphism. For example, Scheme variables and function arguments can hold hold any values. It is up to the code that uses them to use them correctly.

Java variables and method arguments are declared with types that limit the kinds of values they can hold. But Java still supports two kinds of polymorphism.

Overloaded Methods

Consider the operator +. We use + to add numbers. We also use + to concatenate Strings. This is a form of polymorphism, because + works with values of different types. It is called operator overloading. Languages such as C++ allow the programmer to overload operators for the own types, but Java does not.

But this same idea applies to messages, too. In Java, methods are distinguished not only by their names but also by their argument "signatures". Consider constructors. Each class can have multiple constructors, as long as the methods take different kinds or number of arguments.

Then consider the DefaultMemoDatabase class from the memo pad application we studied at the beginning of the semester. This class has an insert method that takes a MemoAssociation as an argument:

    public boolean insert( MemoAssociation newEntry )
      if ( containsKey( newEntry.key() ) )
        return false;

      associations.put( newEntry.key(), newEntry.value() );
      return true;

We could also have an insert method that takes the key and value as arguments, directly:

    public boolean insert( String key, String value )
      if ( containsKey(key) )
        return false;
      associations.put( key, value );
      return true;

The class would then have two methods named insert:

This is another kind of polymorphism, because insert() works with arguments of different types. It is called method overloading. Java allows programmers to overload method names for the own types.

Method overloading is one form of polymorphism supported by Java. It is a useful technique when implementing a single class, as different methods of the same name can respond to messages of the same name differently, depending on the arguments sent by the client code. But if this were all we could do polymorphically in Java, then we would still be quite limited. Client code would have to know the specific kind of object that it was working with at every step of the way.

Polymorphic Variables

Now consider our MultiBallWorld symphony.

To do this without duplicating code, the AWT must store these items in a variable capable of holding any of them, Component. This works because all of these objects respond to the same messages. This is polymorphism across classes, made possible by inheritance. If the classes all implemented the same interface, we could do the same thing.

This is where the real power of polymorphism lies:

Programs that use interchangeable objects can be quite flexible. We will explore this idea throughout the remainder of the course.

Eugene Wallingford ..... ..... October 25, 2012