Шаблон проектирования, заменяющий вложенный переключатель / ifelse - PullRequest
2 голосов
/ 08 ноября 2011

Я работаю на Java, я видел много шаблонов проектирования и пытался вписать в него свою проблему, но почему-то просто не могу найти хороший.

Это примеры пакетов, которые яполучить:

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

Это мой код сейчас:

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 ...

Какой лучший способ сделать это динамически?

Я не хочу добавлять узел в свой ifelse каждый раз, когда я хочу добавить нового робота со всеми его возможными функциями во вложенном ifelse.

Спасибо!

РЕДАКТИРОВАТЬ

Тем временем меня попросили разделить проблему на две части.Переключение между типами роботов будет сделано в другом месте, и я буду использовать шаблон стратегии для переключения между различными типами действий в зависимости от робота.

В любом случае, спасибо за все ответы!Я уверен, что это будет полезно в другой раз или для кого-то еще!

Ответы [ 2 ]

4 голосов
/ 08 ноября 2011

Вы можете использовать диспетчер, следующий псевдокод, не компилируется:

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

тогда у вас есть некоторые настройки:

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() }));

тогда ваш метод становится:

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

Итак, чтобы добавить новое действие, вы добавляете что-то в список. Лучшим способом было бы иметь карту из RobotAction -> Executor; для этого потребуется реализовать equals & hashCode.

2 голосов
/ 08 ноября 2011

Трудно понять, что именно вы пытаетесь сделать именно с ограниченной информацией, но если вы откуда-то получаете кучу «запросов действий» и вам нужно, чтобы разные классы объектов обрабатывали их различными способами, вы сделать что-то вроде этого:

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;
  }
}

Извините, в стиле semi-C # - это то, над чем я работаю сегодня.

Если вы хотите избежать оператора switch в функциях HandleAction, вы можете создать классы ActionExecuter для фактического выполнения таких действий:

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

Тогда есть

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

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

зарегистрирует доступные ActionExecuters с классами, а затем перебирает в обработчике в поиске исполнителя, который может выполнить действие, а затем передает его исполнителю.

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

Это вполне возможно излишне для того, что вы делаете, но тогда все ваши действия и исполнители действий будут полностью инкапсулированы в свои собственные классы.

...