views:

106

answers:

3

Suppose I have a class hierarchy in Java:

interface Item { ... };
class MusicBox implements Item { ... };
class TypeWriter implements Item { ... };
class SoccerBall implements Item { ... };

and I have another class in the same package:

class SpecialItemProcessor {
    public void add(Item item)
    {
        /* X */
    }
}

where I want to do something different for each item type, but I don't want to define that action in the different Item classes (MusicBox, TypeWriter, SoccerBall).

One way to handle this is:

class SpecialItemProcessor {
    public void add(Item item)
    {
        if (item instanceof MusicBox)
        {
            MusicBox musicbox = (MusicBox)item;
            ... do something ...
        }
        else if (item instanceof MusicBox)
        {
            TypeWriter typewriter = (TypeWriter)item;
            ... do something ...
        }
        else if (item instanceof SoccerBall)
        {
            SoccerBall soccerball = (SoccerBall)item;
            ... do something ...
        }
        else
        {
            ... do something by default ...
        }
    }
}

This works but it seems really clunky. Is there a better way to do this, when I know of special cases? (obviously if Item contains a method doSomethingSpecial then I can just call that item's method without caring what type it is, but if I don't want that differentiation to occur within the item itself how do I deal with it?)

A: 

You could create a bridge pattern for Item, in which the other side were the associated processes to do when add() is called. You could also add a factory method to the mix.

class SpecialItemProcessor {
  public void add(Item item)
  {
     Process p = Item.createCorrespondingProcessor( p );
     p.doWhenAddin();
  }
}

Hope this helps.

Baltasarq
What is that syntax? And, how do you use `p` before assigning to it initially?
jjnguy
This isn't PHP... Correct Version: `p.doWhenAddin()`
TheLQ
Sorry, I finally threw in some C++ syntax. This source code is Java. The create corresponding processor method is a factory method that creates the appropriate class corresponding to the class hierarchy of processors, linked to the class hierarchy of Items.
Baltasarq
+5  A: 

In Java you can do multiple dispatch with a visitor(-like) pattern. The Item implementations don't need to contain the processing logic, they just need an accept() type of method.

public interface Item {
/** stuff **/

void processMe(ItemProcessor processor);

}

public interface ItemProcessor {

void process(MusicBox box);

void process(SoccerBall ball);

//etc

}

public class MusicBox implements Item {

  @Override
  public void processMe(ItemProcessor processor) {
    processor.process(this);
  }

}

public class ItemAddingProcessor implements ItemProcessor {

  public void add(Item item) {
    item.processMe(this);
  }

  @Override
  public void process(MusicBox box) {
    //code for handling MusicBoxes
    //what would have been inside if (item instanceof MusicBox) {}
  }

//etc
}
Affe
Hmm. Gives me some ideas, but in your code the interface Item now has a dependency on ItemProcessor which has a dependency on the MusicBox and SoccerBall classes (so not sure if this would even compile)
Jason S
It would compile, you can have cross-dependencies between classes in Java. However, you can't have corss-dependencies between .jars, so it won't work if Item and ItemProcessor are in different .jars.
amorfis
@Jason: yes, it compiles :) It's just a way of flipping things around so that instead of having one method that tries to figure out how to handle the particular type of Item, you have the different types of Items pass themselves in to a method that has their handling. The compile time coupling can be an upside in that, if you had that if-else instanceof block in lots of places around the application, it's much easier to miss updating one when you create a new item type, than when they all implement an interface that changed.
Affe
+1. Adapted a little more cleanly. (see my answer)
Jason S
+1  A: 

I think I'm going to use the idea of inversion of control and the visitor pattern:

interface Item { 
   public void accept(Visitor visitor);
   ... 

   public interface Visitor {
      public void visit(Item item);
   }
}


class MusicBox implements Item { 
   public interface Visitor extends Item.Visitor {
      public void visitMusicBox(MusicBox item);
   }
   ... 
   @Override public accept(Item.Visitor visitor)
   {
      if (visitor instanceof MusicBox.Visitor)
      {
          ((MusicBox.Visitor)visitor).visitMusicBox(this);
      }
   }
}

class TypeWriter implements Item { 
   public interface Visitor extends Item.Visitor {
      public void visitTypeWriter(TypeWriter item);
   }
   ... 
   @Override public accept(Item.Visitor visitor)
   {
      if (visitor instanceof TypeWriter.Visitor)
      {
          ((TypeWriter.Visitor)visitor).visitTypeWriter(this);
      }
   }
}

class SoccerBall implements Item { 
   public interface Visitor extends Item.Visitorr {
      public void visitSoccerBall(SoccerBall item);
   }
   ... 
   @Override public accept(Item.Visitor visitor)
   {
      if (visitor instanceof SoccerBall.Visitor)
      {
          ((SoccerBall.Visitor)visitor).visitSoccerBall(this);
      }
   }
}

and then do the following, which at least reduces the instanceof to one check per add() call:

 class SpecialItemProcessor 
    implements 
       MusicBox.Visitor, 
       TypeWriter.Visitor, 
       SoccerBall.Visitor, 
       Item.Visitor
 {
    public void add(Item item)
    {
        item.accept(this);
    }
    @Override public void visitMusicBox(MusicBox item)
    {
        ...
    }
    @Override public void visitTypeWriter(TypeWriter item)
    {
        ...
    }
    @Override public void visitSoccerBall(SoccerBall item)
    {
        ...
    }
    @Override public void visit(Item item)
    {
        /* not sure what if anything I should do here */
    }
 }
Jason S