【问题标题】: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");
}
方法的实现取决于参数的值。有没有更优雅的方法来做到这一点,或者有不同的设计模式来复制行为?
【问题讨论】:
标签:
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,或者执行您希望执行的任何操作。