Chapter 9. The Iterator and Composite Patterns: Well-Managed Collections

image with no caption

There are lots of ways to stuff objects into a collection. Put them into an Array, a Stack, a List, a Hashmap, take your pick. Each has its own advantages and tradeoffs. But at some point your client is going to want to iterate over those objects, and when he does, are you going to show him your implementation? We certainly hope not! That just wouldn’t be professional. Well, you don’t have to risk your career; you’re going to see how you can allow your clients to iterate through your objects without ever getting a peek at how you store your objects. You’re also going to learn how to create some super collections of objects that can leap over some impressive data structures in a single bound. And if that’s not enough, you’re also going to learn a thing or two about object responsibility.

Breaking News: Objectville Diner and Objectville Pancake House Merge

That’s great news! Now we can get those delicious pancake breakfasts at the Pancake House and those yummy lunches at the Diner all in one place. But, there seems to be a slight problem...

image with no caption

Check out the Menu Items

At least Lou and Mel agree on the implementation of the MenuItems. Let’s check out the items on each menu, and also take a look at the implementation.

image with no caption
image with no caption

Lou and Mel’s Menu implementations

Now let’s take a look at what Lou and Mel are arguing about. They both have lots of time and code invested in the way they store their menu items in a menu, and lots of other code that depends on it.

image with no caption
image with no caption
image with no caption
image with no caption

What’s the problem with having two different menu representations?

To see why having two different menu representations complicates things, let’s try implementing a client that uses the two menus. Imagine you have been hired by the new company formed by the merger of the Diner and the Pancake House to create a Java-enabled waitress (this is Objectville, after all). The spec for the Java-enabled waitress specifies that she can print a custom menu for customers on demand, and even tell you if a menu item is vegetarian without having to ask the cook—now that’s an innovation!

Let’s check out the spec, and then step through what it might take to implement her...

The Java-Enabled Waitress Specification

image with no caption

Let’s start by stepping through how we’d implement the printMenu() method:

  • ① To print all the items on each menu, you’ll need to call the getMenuItems() method on the PancakeHouseMenu and the DinerMenu to retrieve their respective menu items. Note that each returns a different type:

    image with no caption
  • ② Now, to print out the items from the PancakeHouseMenu, we’ll loop through the items on the breakfastItems ArrayList. And to print out the Diner items we’ll loop through the Array.

    image with no caption
  • ③ Implementing every other method in the Waitress is going to be a variation of this theme. We’re always going to need to get both menus and use two loops to iterate through their items. If another restaurant with a different implementation is acquired then we’ll have three loops.

What now?

Mel and Lou are putting us in a difficult position. They don’t want to change their implementations because it would mean rewriting a lot of code that is in each respective menu class. But if one of them doesn’t give in, then we’re going to have the job of implementing a Waitress that is going to be hard to maintain and extend.

It would really be nice if we could find a way to allow them to implement the same interface for their menus (they’re already close, except for the return type of the getMenuItems() method). That way we can minimize the concrete references in the Waitress code and also hopefully get rid of the multiple loops required to iterate over both menus.

Sound good? Well, how are we going to do that?

image with no caption

Yes, using for each would allow us to hide the complexity of the different kinds of iteration. But that doesn’t solve the real problem here: that we’ve got two different implementations of the menus, and the Waitress has to know how each kind of menu is implemented. That’s not really the Waitress’s job. We want her to focus on being a waitress, and not have to think about the type of the menus at all.

image with no caption

Our goal is to decouple the Waitress from the concrete implementations of the menus completely. So hang in there, and you’ll see there’s a better way to do this.

Can we encapsulate the iteration?

If we’ve learned one thing in this book, it’s encapsulate what varies. It’s obvious what is changing here: the iteration caused by different collections of objects being returned from the menus. But can we encapsulate this? Let’s work through the idea...

  • ① To iterate through the breakfast items we use the size() and get() methods on the ArrayList:

    image with no caption
  • ② And to iterate through the lunch items we use the Array length field and the array subscript notation on the MenuItem Array.

    image with no caption
  • ③ Now what if we create an object, let’s call it an Iterator, that encapsulates the way we iterate through a collection of objects? Let’s try this on the ArrayList

    image with no caption
  • ④ Let’s try that on the Array too:

    image with no caption

Meet the Iterator Pattern

Well, it looks like our plan of encapsulating iteration just might actually work; and as you’ve probably already guessed, it is a Design Pattern called the Iterator Pattern.

The first thing you need to know about the Iterator Pattern is that it relies on an interface called Iterator. Here’s one possible Iterator interface:

image with no caption

Now, once we have this interface, we can implement Iterators for any kind of collection of objects: arrays, lists, hashmaps, ...pick your favorite collection of objects. Let’s say we wanted to implement the Iterator for the Array used in the DinerMenu. It would look like this:

image with no caption
image with no caption

Let’s go ahead and implement this Iterator and hook it into the DinerMenu to see how this works...

Adding an Iterator to DinerMenu

To add an Iterator to the DinerMenu we first need to define the Iterator Interface:

image with no caption

And now we need to implement a concrete Iterator that works for the Diner menu:

image with no caption

Reworking the Diner Menu with Iterator

Okay, we’ve got the iterator. Time to work it into the DinerMenu; all we need to do is add one method to create a DinerMenuIterator and return it to the client:

image with no caption

Fixing up the Waitress code

Now we need to integrate the iterator code into the Waitress. We should be able to get rid of some of the redundancy in the process. Integration is pretty straightforward: first we create a printMenu() method that takes an Iterator; then we use the createIterator() method on each menu to retrieve the Iterator and pass it to the new method.

image with no caption

Testing our code

It’s time to put everything to a test. Let’s write some test drive code and see how the Waitress works...

image with no caption

Here’s the test run...

image with no caption

What have we done so far?

For starters, we’ve made our Objectville cooks very happy. They settled their differences and kept their own implementations. Once we gave them a PancakeHouseMenuIterator and a DinerMenuIterator, all they had to do was add a createIterator() method and they were finished.

We’ve also helped ourselves in the process. The Waitress will be much easier to maintain and extend down the road. Let’s go through exactly what we did and think about the consequences:

image with no caption

Hard to Maintain Waitress Implementation

New, Hip Waitress Powered by Iterator

The Menus are not well encapsulated; we can see the Diner is using an ArrayList and the Pancake House an Array.

The Menu implementations are now encapsulated. The Waitress has no idea how the Menus hold their collection of menu items.

We need two loops to iterate through the MenuItems.

All we need is a loop that polymorphically handles any collection of items as long as it implements Iterator.

The Waitress is bound to concrete classes (MenuItem[] and ArrayList).

The Waitress now uses an interface (Iterator).

The Waitress is bound to two different concrete Menu classes, despite their interfaces being almost identical.

The Menu interfaces are now exactly the same and, uh oh, we still don’t have a common interface, which means the Waitress is still bound to two concrete Menu classes. We’d better fix that.

What we have so far...

Before we clean things up, let’s get a bird’s-eye view of our current design.

image with no caption

Making some improvements...

Okay, we know the interfaces of PancakeHouseMenu and DinerMenu are exactly the same and yet we haven’t defined a common interface for them. So, we’re going to do that and clean up the Waitress a little more.

You may be wondering why we’re not using the Java Iterator interface—we did that so you could see how to build an iterator from scratch. Now that we’ve done that, we’re going to switch to using the Java Iterator interface, because we’ll get a lot of leverage by implementing that instead of our home-grown Iterator interface. What kind of leverage? You’ll soon see.

First, let’s check out the java.util.Iterator interface:

image with no caption

This is going to be a piece of cake: we just need to change the interface that both PancakeHouseMenuIterator and DinerMenuIterator extend, right? Almost... actually, it’s even easier than that. Not only does java.util have its own Iterator interface, but ArrayList has an iterator() method that returns an iterator. In other words, we never needed to implement our own iterator for ArrayList. However, we’ll still need our implementation for the DinerMenu because it relies on an Array, which doesn’t support the iterator() method (or any other way to create an array iterator).

Cleaning things up with java.util.Iterator

Let’s start with the PancakeHouseMenu. Changing it over to java.util.Iterator is going to be easy. We just delete the PancakeHouseMenuIterator class, add an import java.util.Iterator to the top of PancakeHouseMenu and change one line of the PancakeHouseMenu:

image with no caption

And that’s it, PancakeHouseMenu is done.

Now we need to make the changes to allow the DinerMenu to work with java.util.Iterator.

image with no caption

We are almost there...

We just need to give the Menus a common interface and rework the Waitress a little. The Menu interface is quite simple: we might want to add a few more methods to it eventually, like addItem(), but for now we will let the chefs control their menus by keeping that method out of the public interface:

image with no caption

Now we need to add an implements Menu to both the PancakeHouseMenu and the DinerMenu class definitions and update the Waitress:

image with no caption

What does this get us?

The PancakeHouseMenu and DinerMenu classes implement an interface, Menu. Waitress can refer to each menu object using the interface rather than the concrete class. So, we’re reducing the dependency between the Waitress and the concrete classes by “programming to an interface, not an implementation.”

Note

This solves the problem of the Waitress depending on the concrete Menus.

The new Menu interface has one method, createIterator(), that is implemented by PancakeHouseMenu and DinerMenu. Each menu class assumes the responsibility of creating a concrete Iterator that is appropriate for its internal implementation of the menu items.

Note

This solves the problem of the Waitress depending on the implementation of the MenuItems.

image with no caption

Iterator Pattern defined

You’ve already seen how to implement the Iterator Pattern with your very own iterator. You’ve also seen how Java supports iterators in some of its collection oriented classes (the ArrayList). Now it’s time to check out the official definition of the pattern:

Note

The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

This makes a lot of sense: the pattern gives you a way to step through the elements of an aggregate without having to know how things are represented under the covers. You’ve seen that with the two implementations of Menus. But the effect of using iterators in your design is just as important: once you have a uniform way of accessing the elements of all your aggregate objects, you can write polymorphic code that works with any of these aggregates—just like the printMenu() method, which doesn’t care if the menu items are held in an Array or ArrayList (or anything else that can create an Iterator), as long as it can get hold of an Iterator.

The Iterator Pattern allows traversal of the elements of an aggregate without exposing the underlying implementation.

It also places the task of traversal on the iterator object, not on the aggregate, which simplifies the aggregate interface and implementation, and places the responsibility where it should be.

The other important impact on your design is that the Iterator Pattern takes the responsibility of traversing elements and gives that responsibility to the iterator object, not the aggregate object. This not only keeps the aggregate interface and implementation simpler, it removes the responsibility for iteration from the aggregate and keeps the aggregate focused on the things it should be focused on (managing a collection of objects), not on iteration.

Let’s check out the class diagram to put all the pieces in context...

image with no caption

Brain Power

The class diagram for the Iterator Pattern looks very similar to another pattern you’ve studied; can you think of what it is? Hint: a subclass decides which object to create.

Single Responsibility

What if we allowed our aggregates to implement their internal collections and related operations AND the iteration methods? Well, we already know that would expand the number of methods in the aggregate, but so what? Why is that so bad?

Well, to see why, you first need to recognize that when we allow a class to not only take care of its own business (managing some kind of aggregate) but also take on more responsibilities (like iteration) then we’ve given the class two reasons to change. Two? Yup, two: it can change if the collection changes in some way, and it can change if the way we iterate changes. So once again our friend CHANGE is at the center of another design principle:

Design Principle

A class should have only one reason to change.

Every responsibility of a class is an area of potential change. More than one responsibility means more than one area of change.

This principle guides us to keep each class to a single responsibility.

We know we want to avoid change in a class like the plague—modifying code provides all sorts of opportunities for problems to creep in. Having two ways to change increases the probability the class will change in the future, and when it does, it’s going to affect two aspects of your design.

The solution? The principle guides us to assign each responsibility to one class, and only one class.

That’s right, it’s as easy as that, and then again it’s not: separating responsibility in design is one of the most difficult things to do. Our brains are just too good at seeing a set of behaviors and grouping them together even when there are actually two or more responsibilities. The only way to succeed is to be diligent in examining your designs and to watch out for signals that a class is changing in more than one way as your system grows.

Brain Power

Examine these classes and determine which ones have multiple responsibilities.

image with no caption
image with no caption

HARD HAT AREA. WATCH OUT FOR FALLING ASSUMPTIONS

Brain2 Power

Determine if these classes have low or high cohesion.

image with no caption
image with no caption
image with no caption

Taking a look at the Café Menu

Here’s the café menu. It doesn’t look like too much trouble to integrate the CafeMenu class into our framework... let’s check it out.

image with no caption

Reworking the Café Menu code

Integrating the CafeMenu into our framework is easy. Why? Because HashMap is one of those Java collections that supports Iterator. But it’s not quite the same as ArrayList...

image with no caption

Adding the Café Menu to the Waitress

That was easy; how about modifying the Waitress to support our new Menu? Now that the Waitress expects Iterators, that should be easy too.

image with no caption

Breakfast, lunch AND dinner

Let’s update our test drive to make sure this all works.

image with no caption

Here’s the test run; check out the new dinner menu from the Café!

image with no caption

What did we do?

image with no caption

We decoupled the Waitress....

image with no caption

... and we made the Waitress more extensible

image with no caption

But there’s more!

image with no caption

Iterators and Collections

We’ve been using a couple of classes that are part of the Java Collections Framework. This “framework” is just a set of classes and interfaces, including ArrayList, which we’ve been using, and many others like Vector, LinkedList, Stack, and PriorityQueue. Each of these classes implements the java.util.Collection interface, which contains a bunch of useful methods for manipulating groups of objects.

image with no caption

Let’s take a quick look at the interface:

image with no caption

Watch it!

Hashtable is one of a few classes that indirectly supports Iterator.

As you saw when we implemented the CafeMenu, you could get an Iterator from it, but only by first retrieving its Collection called values. If you think about it, this makes sense: the HashMap holds two sets of objects: keys and values. If we want to iterate over its values, we first need to retrieve them from the HashMap, and then obtain the iterator.

image with no caption

Is the Waitress ready for prime time?

The Waitress has come a long way, but you’ve gotta admit those three calls to printMenu() are looking kind of ugly.

Let’s be real—every time we add a new menu we are going to have to open up the Waitress implementation and add more code. Can you say “violating the Open Closed Principle”?

image with no caption
image with no caption

It’s not the Waitress’ fault. We have done a great job of decoupling the menu implementation and extracting the iteration into an iterator. But we still are handling the menus with separate, independent objects—we need a way to manage them together.

Brain Power

The Waitress still needs to make three calls to printMenu(), one for each menu. Can you think of a way to combine the menus so that only one call needs to be made? Or perhaps so that one Iterator is passed to the Waitress to iterate over all the menus?

image with no caption

Sounds like the chef is on to something. Let’s give it a try:

image with no caption

This looks pretty good, although we’ve lost the names of the menus, but we could add the names to each menu.

Just when we thought it was safe...

Now they want to add a dessert submenu.

Okay, now what? Now we have to support not only multiple menus, but menus within menus.

It would be nice if we could just make the dessert menu an element of the DinerMenu collection, but that won’t work as it is now implemented.

What we want (something like this):

image with no caption
image with no caption

We can’t assign a dessert menu to a MenuItem array.

Time for a change!

What do we need?

The time has come to make an executive decision to rework the chef’s implementation into something that is general enough to work over all the menus (and now submenus). That’s right, we’re going to tell the chefs that the time has come for us to reimplement their menus.

The reality is that we’ve reached a level of complexity such that if we don’t rework the design now, we’re never going to have a design that can accommodate further acquisitions or submenus.

So, what is it we really need out of our new design?

We need some kind of a tree-shaped structure that will accommodate menus, submenus, and menu items.

We need to make sure we maintain a way to traverse the items in each menu that is at least as convenient as what we are doing now with iterators.

We may need to traverse the items in a more flexible manner. For instance, we might need to iterate over only the Diner’s dessert menu, or we might need to iterate over the Diner’s entire menu, including the dessert submenu.

image with no caption

Note

Because we need to represent menus, nested submenus and menu items, we can naturally fit them in a tree-like structure.

image with no caption

Brain Power

How would you handle this new wrinkle to our design requirements? Think about it before turning the page.

The Composite Pattern defined

That’s right; we’re going to introduce another pattern to solve this problem. We didn’t give up on Iterator—it will still be part of our solution—however, the problem of managing menus has taken on a new dimension that Iterator doesn’t solve. So, we’re going to step back and solve it with the Composite Pattern.

We’re not going to beat around the bush on this pattern; we’re going to go ahead and roll out the official definition now:

Note

Here’s a tree structure.

image with no caption

Note

The Composite Pattern allows you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Let’s think about this in terms of our menus: this pattern gives us a way to create a tree structure that can handle a nested group of menus and menu items in the same structure. By putting menus and items in the same structure we create a part-whole hierarchy; that is, a tree of objects that is made of parts (menus and menu items) but that can be treated as a whole, like one big über menu.

Once we have our über menu, we can use this pattern to treat “individual objects and compositions uniformly.” What does that mean? It means if we have a tree structure of menus, submenus, and perhaps subsubmenus along with menu items, then any menu is a “composition” because it can contain both other menus and menu items. The individual objects are just the menu items—they don’t hold other objects. As you’ll see, using a design that follows the Composite Pattern is going to allow us to write some simple code that can apply the same operation (like printing!) over the entire menu structure.

image with no caption

Note

We can create arbitrarily complex trees.

image with no caption
image with no caption

Note

Operations can be applied to the whole.

image with no caption

Note

Or the parts.

The Composite Pattern allows us to build structures of objects in the form of trees that contain both compositions of objects and individual objects as nodes.

Using a composite structure, we can apply the same operations over both composites and individual objects. In other words, in most cases we can ignore the differences between compositions of objects and individual objects.

image with no caption

Designing Menus with Composite

So, how do we apply the Composite Pattern to our menus? To start with, we need to create a component interface; this acts as the common interface for both menus and menu items and allows us to treat them uniformly. In other words, we can call the same method on menus or menu items.

Now, it may not make sense to call some of the methods on a menu item or a menu, but we can deal with that, and we will in just a moment. But for now, let’s take a look at a sketch of how the menus are going to fit into a Composite Pattern structure:

image with no caption

Implementing the Menu Component

Okay, we’re going to start with the MenuComponent abstract class; remember, the role of the menu component is to provide an interface for the leaf nodes and the composite nodes. Now you might be asking, “Isn’t the MenuComponent playing two roles?” It might well be and we’ll come back to that point. However, for now we’re going to provide a default implementation of the methods so that if the MenuItem (the leaf) or the Menu (the composite) doesn’t want to implement some of the methods (like getChild() for a leaf node) they can fall back on some basic behavior:

Note

All components must implement the MenuComponent interface; however, because leaves and nodes have different roles we can’t always define a default implementation for each method that makes sense. Sometimes the best you can do is throw a runtime exception.

Note

Because some of these methods only make sense for MenuItems, and some only make sense for Menus, the default implementation is UnsupportedOperationException. That way, if MenuItem or Menu doesn’t support an operation, they don’t have to do anything; they can just inherit the default implementation.

image with no caption

Implementing the Menu Item

Okay, let’s give the MenuItem class a shot. Remember, this is the leaf class in the Composite diagram and it implements the behavior of the elements of the composite.

image with no caption
image with no caption

Implementing the Composite Menu

Now that we have the MenuItem, we just need the composite class, which we’re calling Menu. Remember, the composite class can hold MenuItems or other Menus. There’s a couple of methods from MenuComponent this class doesn’t implement: getPrice() and isVegetarian(), because those don’t make a lot of sense for a Menu.

image with no caption
image with no caption

Excellent catch. Because menu is a composite and contains both MenuItems and other Menus, its print() method should print everything it contains. If it didn’t we’d have to iterate through the entire composite and print each item ourselves. That kind of defeats the purpose of having a composite structure.

As you’re going to see, implementing print() correctly is easy because we can rely on each component to be able to print itself. It’s all wonderfully recursive and groovy. Check it out:

Fixing the print() method

image with no caption

Note

NOTE: If, during this iteration, we encounter another Menu object, its print() method will start another iteration, and so on.

Getting ready for a test drive...

It’s about time we took this code for a test drive, but we need to update the Waitress code before we do—after all she’s the main client of this code:

image with no caption

Okay, one last thing before we write our test drive. Let’s get an idea of what the menu composite is going to look like at runtime:

image with no caption

Now for the test drive...

Okay, now we just need a test drive. Unlike our previous version, we’re going to handle all the menu creation in the test drive. We could ask each chef to give us his new menu, but let’s get it all tested first. Here’s the code:

image with no caption

Getting ready for a test drive...

Note

NOTE: this output is based on the complete source.

image with no caption
image with no caption

There is some truth to that observation. We could say that the Composite Pattern takes the Single Responsibility design principle and trades it for transparency. What’s transparency? Well, by allowing the Component interface to contain the child management operations and the leaf operations, a client can treat both composites and leaf nodes uniformly; so whether an element is a composite or leaf node becomes transparent to the client.

Now given we have both types of operations in the Component class, we lose a bit of safety because a client might try to do something inappropriate or meaningless on an element (like try to add a menu to a menu item). This is a design decision; we could take the design in the other direction and separate out the responsibilities into interfaces. This would make our design safe, in the sense that any inappropriate calls on elements would be caught at compile time or runtime, but we’d lose transparency and our code would have to use conditionals and the instanceof operator.

So, to return to your question, this is a classic case of tradeoff. We are guided by design principles, but we always need to observe the effect they have on our designs. Sometimes we purposely do things in a way that seems to violate the principle. In some cases, however, this is a matter of perspective; for instance, it might seem incorrect to have child management operations in the leaf nodes (like add(), remove() and getChild()), but then again you can always shift your perspective and see a leaf as a node with zero children.

Flashback to Iterator

We promised you a few pages back that we’d show you how to use Iterator with a Composite. You know that we are already using Iterator in our internal implementation of the print() method, but we can also allow the Waitress to iterate over an entire composite if she needs to—for instance, if she wants to go through the entire menu and pull out vegetarian items.

To implement a Composite iterator, let’s add a createIterator() method in every component. We’ll start with the abstract MenuComponent class:

image with no caption

Now we need to implement this method in the Menu and MenuItem classes:

image with no caption

The Composite Iterator

The CompositeIterator is a SERIOUS iterator. It’s got the job of iterating over the MenuItems in the component, and of making sure all the child Menus (and child child Menus, and so on) are included.

Here’s the code. Watch out. This isn’t a lot of code, but it can be a little mind bending. As you go through it just repeat to yourself “recursion is my friend, recursion is my friend.”

image with no caption

WATCH OUT: RECURSION ZONE AHEAD

image with no caption
image with no caption

When we wrote the print() method in the MenuComponent class we used an iterator to step through each item in the component, and if that item was a Menu (rather than a MenuItem), then we recursively called the print() method to handle it. In other words, the MenuComponent handled the iteration itself, internally.

With this code we are implementing an external iterator so there is a lot more to keep track of. For starters, an external iterator must maintain its position in the iteration so that an outside client can drive the iteration by calling hasNext() and next(). But in this case, our code also needs to maintain that position over a composite, recursive structure. That’s why we use stacks to maintain our position as we move up and down the composite hierarchy.

Brain Power

Draw a diagram of the Menus and MenuItems. Then pretend you are the CompositeIterator, and your job is to handle calls to hasNext() and next(). Trace the way the CompositeIterator traverses the structure as this code is executed:

public void testCompositeIterator(MenuComponent component) {
       CompositeIterator iterator = new CompositeIterator(component.iterator);

       while(iterator.hasNext()) {
              MenuComponent component = iterator.next();
       }
}

The Null Iterator

Okay, now what is this Null Iterator all about? Think about it this way: a MenuItem has nothing to iterate over, right? So how do we handle the implementation of its createIterator() method? Well, we have two choices:

Note

NOTE: Another example of the Null Object “Design Pattern.”

Choice one:

  • Return null

  • We could return null from createIterator(), but then we’d need conditional code in the client to see if null was returned or not.

Choice two:

  • Return an iterator that always returns false when hasNext() is called

  • This seems like a better plan. We can still return an iterator, but the client doesn’t have to worry about whether or not null is ever returned. In effect, we’re creating an iterator that is a “no op.”

The second choice certainly seems better. Let’s call it NullIterator and implement it.

image with no caption

Give me the vegetarian menu

Now we’ve got a way to iterate over every item of the Menu. Let’s take that and give our Waitress a method that can tell us exactly which items are vegetarian.

image with no caption

The magic of Iterator & Composite together...

Whooo! It’s been quite a development effort to get our code to this point. Now we’ve got a general menu structure that should last the growing Diner empire for some time. Now it’s time to sit back and order up some veggie food:

image with no caption
image with no caption

Let’s take a look at what you’re talking about:

image with no caption

In general we agree; try/catch is meant for error handling, not program logic. What are our other options? We could have checked the runtime type of the menu component with instanceof to make sure it’s a MenuItem before making the call to isVegetarian(). But in the process we’d lose transparency because we wouldn’t be treating Menus and MenuItems uniformly.

We could also change isVegetarian() in the Menus so that it returns false. This provides a simple solution and we keep our transparency.

In our solution we are going for clarity: we really want to communicate that this is an unsupported operation on the Menu (which is different than saying isVegetarian() is false). It also allows for someone to come along and actually implement a reasonable isVegetarian() method for Menu and have it work with the existing code.

That’s our story and we’re stickin’ to it.

Tools for your Design Toolbox

Two new patterns for your toolbox—two great ways to deal with collections of objects.

image with no caption
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.19.31.73