RU beehive logo ITEC dept promo banner
ITEC 120
2008spring
ibarland,
jdymacek

homeinfoarchiveexamslectureslabshws
RecipeLawsliessyntaxjava.lang docsjava.util docs

lect14c
The Delegate Pattern
Guard Dogs

…continuing our discussion on inheritance and interfaces.

The Delegate Pattern

How to fake multiple inheritance, if Java doesn't allow it? That is, suppose we have Guard Dogs, which are like Dogs but they have some additional guard behaviours:

  String threatenSound();             // How does this guard threaten?
  boolean deters(Animal anAnimal);    // Does this guard succesfully deter anAnimal?
In fact, we quickly realize that being a guard is not specific to being a Dog; we could certainly have guard-cats and guard-pythons. In fact, some guards aren't even animals -- an alarm system can make a threatening sound and can deter some (human) animals. So we should have Guard be its own class. (There is code for the Guard methods.

But now we have the problem, that for a class GuardDog we want to Extend two different classes.

This is better, but not a perfect solution. For instance: And, if we want to make a SmallGuardDog, what class should it extend — GuardDog, or SmallDog? Either answer is unsatisfactory. Delegate pattern can still help, though it's starting to become cumbersome: for every class we can have an interface, and then have SmallGuardDog extend SmallDog implement IGuardDog2, and it will have a GuardDog2 delegate instance inside of it. This avoids repeated code (at the cost of our mental overhead).


The Command Pattern (optional)

In lab14a—home photoshopping network: arrays of pixels, we saw that we might want to write many many ways of modifying an image. Each method does specific processing of individual pixels, but each of those methods probably has repeated code: a loop to process an entire row of pixels, and another loop to process all the rows of the entire image.

We'd like to avoid that repetition, and only write the do-one-row and do-entire-image loops once. In fact, we'd like to say

Hey image -- I'll pass you a method which processes one single pixel, and I want you to apply this method to every pixel you have.
Unfortunately, Java does not let us pass around methods. But here's how we can fake it, using the command pattern:
class MyEffects {
  //... other methods omitted
 

  /** Process an entire image by giving each of our pixels to a PixelProcessor
    * to be worked on.
    * @param p A particular PixelProcessor object.
    */
  public void doAll( PixelProcessor p ) {
    // Call p.doPixel on each pixel of data[][].
    // See below for the full code.
    }
You can think of class PixelProcessor as “the method I want to give to somebody else to use”.
import java.awt.Color;

/** An interface with a single method: process one pixel of an image.
 */
interface PixelProcessor {

  /** Process one particular pixel in an image.
   * @param r The row of `data` our pixel is in.
   * @param c The column of `data` our pixel is in.
   * @param data The array of pixels; we may change the contents of data[][] --
   *      in particular, we'll probably modify data[r][c] but nothing else.
   */
  void doPixel( int r, int c, Color[][] data );

  }
Now, the code to filter red from a pixel is (a method inside of) its very own class:
/** A PixelProcessor which removes everything but the redness
 * from a pixel.
 */
class RedFilterer implements PixelProcessor {
  
  void doPixel( int r, int c, Color[][] data ) {
    Color k = data[r][c];
    int existingRed= k.getRed();
    data[r][c] = new Color( existingRed, 0, 0 );
    } 
and similarly code which converts to black-and-white is (a method inside of) its very own class:
/** A PixelProcessor which converts the pixel to black-and-white.
 */
class BWConverter implements PixelProcessor {
  
  void doPixel( int r, int c, Color[][] data ) {
    Color k = data[r][c];
    int brightness = (k.getRed()  + k.getBlue() + k.getGreen()) / 3;
    data[r][c] = new Color( brightness, brightness, brightness );
    } 
And we can have a hundred other processors, which don't have to be put in the same file with any existing ones:
/** A PixelProcessor which makes a pixel bright if it differs greatly
 * from its neighbor to the right or the neighbor below.
 */
class EdgeDetector implements PixelProcessor {
  
  void doPixel( int r, int c, Color[][] data ) {
    Color here = data[r][c];

    Color below =  (r+1 >= data.length) ? data[r+1][c] : here;
    Color right  =  (c+1 >= data[0].length) ? data[r][c+1] : here;
    // If we are at the edge, consider our neighbor to be ourself.
    // This works okay, because when we take the difference between
    // self and neighbor, we'll get 0, which is a reasonable notion of 'difference'.

    int newRed = Math.max( Math.abs( here.getRed() - below.getRed() ),
 	       	 	               Math.abs( here.getRed() - right.getRed() ) );
    int newGreen = Math.max( Math.abs( here.getGreen() - below.getGreen() ),
 	      	                          Math.abs( here.getGreen() - right.getGreen() ) );
    int newBlue = Math.max( Math.abs( here.getBlue() - below.getBlue() ),
     	       	 	               Math.abs( here.getBlue() - right.getBlue() ) );

    data[r][c] = new Color( newRed, newGreen, newBlue );
    }
  /* BUG: this code is relying on the fact that the pixels below and to the right
   * are the *original* image (not already modifed for their edges).
   * This happens to be true, but *only* because MyEffects happens to 
   * work top-to-bottom, left-to-right.
   *
   * In fact, we realize that some special effects shouldn't modify the image 
   * they're working with; they should leave it untouched so future pixels
   * also know what the original picture was.
   * So instead of modifying the current pixel data[r][c], they should instead
   * be creating pixel r,c of a *new* picture (a new Color[][]).
   * Perhaps two arrays should be passed in to doPixel: 
   * the original, unchanged source, and a new array which we're filling.
   * This modification to the architecture is left to the reader.
   */
    }
Now, back in MyEffects, if we want to apply this
   // Inside class MyEffects

  public void doAll( PixelProcessor p ) {
    for (int r= 0;  r < data.length;  ++r ) {
      doRow(p, r);
      }
    }
    
  /** Process one row of an image
   * by giving each pixel in the row to the PixelProcessor p.
   *  (modifying the contents of data[][])
   * @param rowNum the row of data to process.
   */  
  private void doRow( PixelProcessor p, int rowNum) {
    for (int c= 0;  c < data[rowNum].length;  ++c ) {
      p.doPixel( rowNum, c, data );
      } 
Finally, we run the code by doing something like
this.doAll( new EdgeDetector() )
this.doAll( new RedFilter() )

What has all this gained us?

Note that the compareTo interface is (nearly) an instance of the command pattern: instead of passing in a method compareTo as an argument, and instead of passing an object which contains the compareTo method, we make sure that the object in question already has a compareTo method inside of it.

homeinfoarchiveexamslectureslabshws
RecipeLawsliessyntaxjava.lang docsjava.util docs


©2008, Ian Barland, Radford University
Last modified 2008.Apr.25 (Fri)
Please mail any suggestions
(incl. typos, broken links)
to iba�rlandrad�ford.edu
Powered by PLT Scheme