Java - 方法实现取决于参数值

4
考虑一种方法
public void doSomething(String actionID){
switch (actionID){
    case "dance":
            System.out.print("I'm dancing");
            break;
    case "sleep":
            System.out.print("I'm sleeping");
            break;
    default: 
            System.out.print("I've no idea what I'm doing");
}

该方法的实现取决于参数的值。是否有更优雅的方式来做这个,或者使用不同的设计模式来复制这种行为?


你可能正在寻找类似这样的东西吗?http://crunchify.com/why-and-for-what-should-i-use-enum-java-enum-examples/ - M. Mariscal
4
您可以实现一个命令模式。 - Tim Biegeleisen
4个回答

4
如果调用者通过传递不同的字符串来决定执行什么逻辑,那么为什么不让他们调用不同的方法呢:
public void doSomething(String actionID) {...}
...
doSomething("dance");
doSomething("sleep");

VS.:

public void dance() {...}
public void sleep() {...}
...
dance();
sleep();

看起来你在不必要地将所有的调用都汇聚到 doSomething 中。


但这些字符串可能并不总是字面量。如果它们来自控制台怎么办?

你可以提供从字符串到相应函数的静态映射:

class MyClass {
    private static final Map<String, Consumer<MyClass>> map = new HashMap<>();

    static {
        map.put("sleep", MyClass::sleep);
        map.put("dance", MyClass::dance);
    }

    public void doSomething(String actionID) {
        map.getOrDefault(actionID, MyClass::doNothing).accept(this);
    }

    public void dance() {
        System.out.print("I'm dancing");
    }

    public void sleep() {
        System.out.print("I'm sleeping");
    }

    private void doNothing() {
        System.out.println("I've no idea what I'm doing");
    }
}

这样可以使得有大量switch case情况下的代码更加简洁易读。

1
介绍一个接口,例如:
  public interface HumanState {

    public void tellMeWhatYouAreDoing();
  }

封装逻辑在不同的实现中。
  public class DancingState implements HumanState {
    @Override
    public void tellMeWhatYouAreDoing() {
      System.out.println("I'm dancing");
    }
  }

  public class SleepingState implements HumanState {

    @Override
    public void tellMeWhatYouAreDoing() {
      System.out.println("I'm sleeping");
    }
  }

  public class UnknownState implements HumanState {

    @Override
    public void tellMeWhatYouAreDoing() {
      System.out.println("I've no idea what I'm doing");
    }
  }

使用地图。例如:
public class HumanStateExample {

  public static void main(String[] args) {
    HumanStateExample humanStateExample = new HumanStateExample();

    humanStateExample.doSomething("dance");
    humanStateExample.doSomething("sleep");
    humanStateExample.doSomething("unknown");
  }

  private final HashMap<String, HumanState> humanStateMap;


  public HumanStateExample(){
    humanStateMap = new HashMap<String, HumanState>();
    humanStateMap.put("dance", new DancingState());
    humanStateMap.put("sleep", new SleepingState());

  }

  public void doSomething(String action) {
    HumanState humanState = humanStateMap.get(action);
    if(humanState == null){
      humanState = new UnknownState();
    }

    humanState.tellMeWhatYouAreDoing();
  }
}

1

我不确定这种模式叫什么,但如果你需要基于多个参数委托方法调用,它非常有用:

创建许多处理程序,每个处理程序都知道何时负责处理调用。然后只需循环遍历它们并调用与参数匹配的第一个。

编辑:我将FancyParameterActionFactory类重命名为FancyParameterActionUtility:它不是工厂,名称会引起误解。

//Your method, but this time with a complex object, not with a simple string.
public void doSomething(FancyParameterObject fpo){
    FancyParameterActionUtility.invokeOn(fpo);
}


 //The utility which can handle the complex object and decides what to do.
public class FancyParameterActionUtility{
    public Interface FPAHandler{
        void invoke(FancyParameterObject fpo);
        boolean handles(FancyParameterObject fpo);
    }

    //Omitted: Different implementations of FPAHandler

    public static List<FPAHandler> handlers = new LinkedList<>();

    static{
        handlers.add(new DanceHandler());
        handlers.add(new SleepHandler());
        //Omitted: Different implementations of FPAHandler
    }

    public static void invokeOn(FancyParameterObject fpo){
        for(FPAHandler handler:handlers){
            if (handler.handles(fpo)){
                handler.invoke(fpo);
                return;
            }
        }
        //Default-Behavior
    }

}

0

这是一个基于您的示例问题的命令模式的简单实现。我定义了一个通用的AbstractCommand抽象类,其中包含两个方法。第一个方法createCommand()根据输入字符串名称实例化一个命令类。这是您如何将字符串输入委派给创建正确类型的命令。第二个方法是doAction(),这个方法没有定义,稍后由具体的命令类实现。

public abstract class AbstractCommand {
    public static AbstractCommand createCommand(String name) {
        try {
            String clsName = name + "Command";
            Class<?> cls = Class.forName(clsName);
            AbstractCommand command = (AbstractCommand) cls.newInstance();

            return command;
        }
        catch (Exception e) {
            System.out.println("Something went wrong.");
        }
    }

    public abstract void doAction();
}

public class DanceCommand extends AbstractCommand {
    public void doAction() {
        System.out.println("I'm dancing");
    }
}

public class TestCommandPattern {
    public void doSomething(String actionID) {
        AbstractCommand cmd = AbstractCommand.createCommand(actionID);
        cmd.doAction();
    }

    public static void main(String[] args) {
        TestCommandPattern test = new TestCommandPattern();
        test.doSomething("Dance");  // should print "I'm dancing"
    }
}

现在这个框架已经设置好了,你可以轻松地为原始问题中的各种类型的操作添加其他命令。例如,你可以创建一个SleepCommand类,它会输出我正在睡觉,或者执行任何你想要的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接