【问题标题】:Java - Method implementation dependent from parameter valueJava - 方法实现取决于参数值
【发布时间】:2016-09-08 03:21:18
【问题描述】:

考虑一个方法

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

方法的实现取决于参数的值。有没有更优雅的方法来做到这一点,或者有不同的设计模式来复制行为?

【问题讨论】:

  • 您可能正在寻找类似的东西吗? crunchify.com/…
  • 你可以实现一个命令模式。

标签: java oop design-patterns methods


【解决方案1】:

如果调用者通过传递不同的字符串来决定执行什么逻辑,那么为什么不让它们调用不同的方法:

public void doSomething(String actionID) {...}
...
doSomething("dance");
doSomething("sleep");

对比:

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 的场景更加清晰。

【讨论】:

    【解决方案2】:

    我不确定该模式是如何调用的,但是如果您需要基于多个参数委托方法调用,它非常有用:

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

    编辑:我将类从 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
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      引入一个接口,例如

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

      【讨论】:

        【解决方案4】:

        这是基于您的示例问题的命令模式的简单实现。我定义了一个通用的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 类,该类将输出I'm sleeping,或者执行您希望执行的任何操作。

        【讨论】:

          猜你喜欢
          • 2018-12-16
          • 1970-01-01
          • 1970-01-01
          • 2012-02-07
          • 1970-01-01
          • 2017-02-22
          • 1970-01-01
          • 2015-12-22
          • 1970-01-01
          相关资源
          最近更新 更多