Session 30

Composite Objects and a Few Principles


CS 2530
Intermediate Computing


Where Are We?

Last session, we learned about the strategy pattern. A strategy is an object that executes the piece of an algorithm that changes. This allows us to customize an an algorithm by passing the part that changes as a parameter.

We used a strategy object to implement a Play class that counts the words in its text that satisfy an arbitrary test. The test is passed as an argument to the word-counting method.

To do this, we created an interface for our strategy objects:

    public interface WordFeature
    {
      public boolean hasFeature( String s );
    }

Then we wrote several strategies, including one that finds words that start with a particular character and one that finds words of a particular length.

The folks in the English department are pleased with us! They study texts to determine who the author was, based on stylistic criteria such as average word length, number of different words, and so on. Our program allows them to do this much more easily than before.

But...



Your Final Bow

Now they want more. (Clients... Sheesh.)

They would like to be able to combine tests, such as
count all the 4-letter words that start with 's'.

You think to yourself, Hey, I know just what to do! Doing two tests at once is just another kind of test. All I need is another class that implements WordFeature.

You always knew that the effort you put into Intermediate Computing would be worth it some day.

Write a WordFeature class
to meet our clients' new need.

Do it now, please. (Humor me one last time...)



A Series of Solutions

Here is the simplest solution I could create, using copy-and-paste. It gets the job done, but it is not very flexible. How could it be better?

First of all, it repeats code from StartsWith and OfLength. This repetition is a sign that my class is doing too much. It should be lazier! Here is a solution that creates helper objects. It solves the problem with less duplication. But it still does too much work.

The code that creates a StartsWithOfLength object knows that it needs StartsWith and OfLength tests. So that code should create them! Here is a solution that receives its helper objects as arguments. It solves the client's new problem but leaves the responsibility for creating the tests to the client code.

Now we are ready to handle the flexibility problem. Why hardcode the tests in our new class to the StartsWith and OfLength classes? Our clients "would like to be able to combine tests, such as count all the 4-letter words that start with 's'". If our class accepted any two WordFeatures, then it could be used for other combinations.

Here is a solution that accepts any two WordFeatures as arguments. Look how little code this class requires. It repeats no code. It defers as much work as possible to the code that uses it, eliminating the need to know anything about that code's details.

I have renamed my class CompoundFeature now, because it is no longer a class of StartsWithOfLength tests. It is the class for any compound test built out of two other tests.

I like this solution very much.



A Quick Note on Programming

We now have a solution that is even simpler than our first solution, but it is much more flexible. We started with something that was easy to create and relatively simple, and then let it evolve as we addressed its weaknesses and applied basic principles of OO programming.

Programs evolve like this all time. Often, our job is to guide their evolution as the environment around them changes: the client's needs and desires, our programming experience, and the other code that lives around them. You can write most code in this way, and often end up with a better solution than you could have created from scratch.



The Composite Pattern

Think again about what we have done with CompoundFeature. We have created an object that acts like a single test but that does two tests. Each of these tests is just ... a single test, like the ones we've created and used before.

Does this sound familiar? It is very much like a Panel in the AWT or a SequenceInputStream, one of the virtual input streams in the java.io package. They are all examples of the composite design pattern.

A composite is an object that acts like one object but is, in fact, coordinating the work of several objects. Here is a simple class diagram:

the composite design pattern

You will encounter composites throughout the world of objects. They are a handy way to write flexible, extendible code using substitutable objects.

Composites don't exist only in the OOP world. You will find them all over the world of programs. For example, a directory or folder in an operating system is a composite file, made up of other files (maybe even other directories). In both the world of program and the worls of mathematics, arithmetic expressions are composites built out of other expressions.

You can even find composities in your kitchen! Many recipes include ingredients that are themselves made from recipes. (You should taste my chocolate cream pie with meringue!)

You may notice that the diagram for the composite pattern looks a lot like the diagram for a decorator. How are these two patterns similar? How are they different?



A Final Version of CompoundFeature

Our current CompoundFeature class has two other tests do much of its work. We can make our solution even more flexible by having the class maintain a collection of tests, such as a Vector. This generalizes our solution one more step to let the compound test perform any number of tests.

Now, when the client asks for a three-part test, we can deliver the solution for free!

(My class starts with an empty vector and provides an add() method, so that user can add tests one at a time. An alternative would be for the constructor to accept an already created vector, or something more generic. What are the relative advantages of my approach? Of the second approach?)

So, what's the answer? Let's run our new compound test:

    > java WordLengths hamlet.txt 10 t
    The document in the file hamlet.txt contains ...
         96 words of 1 characters
         843 words of 2 characters
         1351 words of 3 characters
         1441 words of 4 characters
         463 words of 5 characters
         141 words of 6 characters
         81 words of 7 characters
         66 words of 8 characters
         31 words of 9 characters
         14 words of 10 characters
     ... that start with 't'.

    > java WordLengths declaration-of-independence.txt 15 a
    The document in the file declaration-of-independence.txt contains ...
         197 words of 1 characters
         156 words of 2 characters
         779 words of 3 characters
         35 words of 4 characters
         61 words of 5 characters
         ...
         33 words of 11 characters
         10 words of 12 characters
         6 words of 13 characters
         10 words of 14 characters
         0 words of 15 characters
     ... that start with 'a'.

We are well on our way to building analytic tools that would help us confirm Shakespeare as the author of his plays, or someone else.



Your Burning Questions

A lot of your questions dealt with how to use Java to do some task that interests you. Java has an extensive class library, and Java programmers have produced many useful libraries to extend the language. One goal of this course is that you know enough about Java and OOP that you can learn new package well, whether standard or custom. So:

Then there were a few general questions to which I can give general answers:

Finally, there were a couple of cool questions about taking the next step as a Java programmer.

Keep asking questions. That is how you get better.



Some Final Ideas on Object-Oriented Design

Note: I have not had a chance to write these up in narrative form yet, but this stream-of-consciousness dump should jog your memory about we talked about in class. Feel free to follow up with any questions you have.

Laziness. Eliminate duplication by using objects, not copyig their code. Distributes control, creates more capable collaborators.

Ignorance and apathy. Encapsulation. Substitutability.

I have identified a few of the ideas that summarize what we have learned about object-oriented design and programming. I have borrowed these liberally from Alan Knight's excellent article Principles of OO Design (Part 1) or, Everything I know about programming, I learned from Dilbert.



Are There Any Final Questions?


is it over yet???

The most common final question at this point is usually about the final: "What's on the exam?" Here is a high-level checklist:

Feel free to ask questions about any of these, or anything else.



Wrap Up



Eugene Wallingford ..... wallingf@cs.uni.edu ..... December 7, 2012