Abstracting usage

Bruce Eckel's Thinking in Java Contents | Prev | Next

With creation out of the way, it’s time to tackle the remainder of the design: where the classes are used. Since it’s the act of sorting into bins that’s particularly ugly and exposed, why not take that process and hide it inside a class? This is the principle of “If you must do something ugly, at least localize the ugliness inside a class.” It looks like this:

The TrashSorter object initialization must now be changed whenever a new type of Trash is added to the model. You could imagine that the TrashSorter class might look something like this:

class TrashSorter extends Vector {
  void sort(Trash t) { /* ... */ }
}

That is, TrashSorter is a Vector of handles to Vectors of Trash handles, and with addElement( ) you can install another one, like so:

TrashSorter ts = new TrashSorter();

ts.addElement(new Vector());

Now, however, sort( ) becomes a problem. How does the statically-coded method deal with the fact that a new type has been added? To solve this, the type information must be removed from sort( ) so that all it needs to do is call a generic method that takes care of the details of type. This, of course, is another way to describe a dynamically-bound method. So sort( ) will simply move through the sequence and call a dynamically-bound method for each Vector. Since the job of this method is to grab the pieces of trash it is interested in, it’s called grab(Trash). The structure now looks like:

TrashSorter needs to call each grab( ) method and get a different result depending on what type of Trash the current Vector is holding. That is, each Vector must be aware of the type it holds. The classic approach to this problem is to create a base “ Trash bin” class and inherit a new derived class for each different type you want to hold. If Java had a parameterized type mechanism that would probably be the most straightforward approach. But rather than hand-coding all the classes that such a mechanism should be building for us, further observation can produce a better approach.

//: RecycleB.java
// Adding more objects to the recycling problem
package c16.recycleb;
import c16.trash.*;
import java.util.*;
 
// A vector that admits only the right type:
class Tbin extends Vector {
  Class binType;
  Tbin(Class binType) { 
    this.binType = binType; 
  }
  boolean grab(Trash t) {
    // Comparing class types:
    if(t.getClass().equals(binType)) {
      addElement(t);
      return true; // Object grabbed
    }
    return false; // Object not grabbed
  }
}
 
class TbinList extends Vector { //(*1*)
  boolean sort(Trash t) {
    Enumeration e = elements();
    while(e.hasMoreElements()) {
      Tbin bin = (Tbin)e.nextElement();
      if(bin.grab(t)) return true;
    }
    return false; // bin not found for t
  }
  void sortBin(Tbin bin) { // (*2*)
    Enumeration e = bin.elements();
    while(e.hasMoreElements())
      if(!sort((Trash)e.nextElement()))
        System.out.println("Bin not found");
  }
}
 
public class RecycleB {
  static Tbin bin = new Tbin(Trash.class);
  public static void main(String[] args) {
    // Fill up the Trash bin:
    ParseTrash.fillBin("Trash.dat", bin);
 
    TbinList trashBins = new TbinList();
    trashBins.addElement(
      new Tbin(Aluminum.class));
    trashBins.addElement(
      new Tbin(Paper.class));
    trashBins.addElement(
      new Tbin(Glass.class));
    // add one line here: (*3*)
    trashBins.addElement(
      new Tbin(Cardboard.class));
 
    trashBins.sortBin(bin); // (*4*)
 
    Enumeration e = trashBins.elements();
    while(e.hasMoreElements()) {
      Tbin b = (Tbin)e.nextElement();
      Trash.sumValue(b);
    }
    Trash.sumValue(bin);
  }
} ///:~ 

  1. TbinList holds a set of Tbin handles, so that sort( ) can iterate through the Tbins when it’s looking for a match for the Trash object you’ve handed it.
  2. sortBin( ) allows you to pass an entire Tbin in, and it moves through the Tbin, picks out each piece of Trash, and sorts it into the appropriate specific Tbin. Notice the genericity of this code: it doesn’t change at all if new types are added. If the bulk of your code doesn’t need changing when a new type is added (or some other change occurs) then you have an easily-extensible system.
  3. Now you can see how easy it is to add a new type. Few lines must be changed to support the addition. If it’s really important, you can squeeze out even more by further manipulating the design.
  4. One method call causes the contents of bin to be sorted into the respective specifically-typed bins.


Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: January 28, 2015 @ 11:00 a.m. ET / 8:00 a.m. PT Check out this upcoming live webcast and join Jeff Sloyer, IBM Developer Evangelist and Master Inventor, for a tutorial for building cloud-based applications. Using IBM's platform as a service, Bluemix, Jeff will show you how to architect and assemble cloud-based applications built for cloud scale. Leveraging the power of microservices, developers can quickly translate monolithic applications to a cloud-based microarchitecture. This hour-long …

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date