Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dispatch design pattern?

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?)

like image 514
Jason S Avatar asked Sep 08 '10 21:09

Jason S


3 Answers

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
}
like image 147
Affe Avatar answered Sep 28 '22 01:09

Affe


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 */
    }
 }
like image 37
Jason S Avatar answered Sep 28 '22 03:09

Jason S


Why not define some callback function to Item interface?

public Interface Item {
  void onCallBack();
}

Then in each class that implements Item, such as MusicBox, it should implement the callback function.

public class MusicBox {
  @override
  public void onCallBack() {
    // business logic
    ...
    ...  
  }
}

Then you could create a dispatcher, which you name is "SpecialItemProcessor".

public SpecialItemProcessor {
  private final Item _item;

  public SpecialItemProcessor(Item item) {
    _item = item;
  }

  public dispatch() {
    _item.onCallBack()
  }
}

And then, in the Client class which contains the SpecialItemProcessor could just call the method, like:

public void XXXX() {
  ....
  SpecialItemProcessor specialItemProcessor = new SpecialItemProcessor(new MusicBox());
  specialItemProcessor.dispatch();
  ....
}

Actually, in C++, this is Dynamic Binding. And this is why pure abstract class exists...

like image 20
Cherish Avatar answered Sep 28 '22 01:09

Cherish