hhoud
hhoud

Reputation: 518

Design Pattern replacing nested switch/ifelse

I'm working in Java and I've seen a lot of design patterns and tried to fit my problem in it but somehow I just can't find the good one.

These are example packets I receive:

{String robot, String action, int duration}
{"Humanoid", "Forward", 2}
{"Humanoid", "Backward", 5}
{"Snatcher", "Grab"}

This is my code now:

if "humanoid" {
    if "forward" {
        humanoid.forward(duration);
    }
    if "backward" {
        humanoid.backward(duration);
    }
    ...
}else if "snatcher" {
    if "forward" {
        snatcher.forward(duration);
    }
    if "grab" {
        snatcher.grab();
    }
}
elseif ...

What's the best way to do this dynamically?

I don't want to add a node to my ifelse everytime I'd like to add a new robot with all of its possible functions in the nested ifelse.

Thanks!

EDIT

In the mean time I've been asked to split the problem in two parts. The switch between types of robots will be done elsewhere and I'll use Strategy Pattern to switch between the different types of actions depending on the robot.

Anyway, thanks for all the answers! I'm sure it will be useful another time or for somebody else!

Upvotes: 2

Views: 1961

Answers (2)

Russell Troywest
Russell Troywest

Reputation: 8776

Hard to know what it is you're trying to do exactly with the limited information but if you're getting a bunch of "action requests" from somewhere and need to have different classes of object process them in different ways you could do something like this:

interface IActionHandler{
  void HandleAction(Action action);
}

class Humanoid: IActionHandler{
  void HandleAction(Action action){
    switch(action.ActionType){
       ActionType.Forward: Forward();
      ......
    }
  }
...
}

class Catcher: IActionHandler{
  void HandleAction(Action action){
    switch(action.ActionType){
       ActionType.Grab: Grab();
      ......
    }
  }
...
}

class MainActionReceiver{
  ReceiceActionRequest(Action action){
    GetActioner(action.Actioner).HandleAction(action);
  }

  IActionHander GetActioner(string actioner){
    if (actioner == "Humanoid"){
      return humanoidObject;
    }
    return catcherObject;
  }
}

Excuse the semi-C# style - it's what I'm working in today.

If you wanted to avoid the switch statement in the HandleAction functions you could create ActionExecuter classes to actually execute the actions like this:

Interface IExecuter<T>{   
  bool CanExecute(Action action)
  void Execute(T owner, Action action); 
}

Then have

class ForwardExecuter<Humanoid>{
  bool CanExecute{
    return action.ActionType == forward;
  }

  Execute(Humaniod owner, Action action){
    owner.Forward();
  }
}

register the available ActionExecuters with the classes and then loop through the in the Handler looking for an Executer that can execute the action and then pass this to the executer.

class Humanoid: IActionHandler{
  void HandleAction(Action action){
    foreach (IExecuter in executers){
      if (executer.CanExecute(action)){
        executer.Execute(this, action);
      }
    }
  }
...
}

That's quite possibly overkill for what you are doing, but you then have all your actions and action executers cleanly encapsulated in their own classes.

Upvotes: 2

Matthew Farwell
Matthew Farwell

Reputation: 61695

You could use a dispatcher, the following is pseudo code, doesn't compile:

interface Executor { public void execute(); }
class RobotAction {
    String robot;
    String action;
    Executor executor;
}

then you have some setup:

list.add(new RobotAction("Humanoid", "Forward", new Executor() { public void execute() { humanoid.forward(5) }));
list.add(new RobotAction("Humanoid", "Backward", new Executor() { public void execute() { humanoid.backward(2) }));
list.add(new RobotAction("Snatcher", "Grab", new Executor() { public void execute() { snatcher.grab() }));

then your method becomes:

public void dispatch(String robot, String action) {
    for (RobotAction robotAction : list) {
         if (robot.equals(robotAction.robot) && action.equals(robotAction.action)) {
             robotAction.execute();
         }
    }
}

So to add a new action, you add something to the list. A better method would be to have a map from RobotAction -> Executor; this would require you to implement equals & hashCode.

Upvotes: 4

Related Questions