使用 java lambdas 重构 switch case
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33603856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Refactor a switch case with java lambdas
提问by Sudheer
I am trying to re-factor a legacy code and in this case I have a huge block of switch case which decide which command to be executed
我正在尝试重构遗留代码,在这种情况下,我有一大块 switch case 来决定要执行的命令
switch(operation)
case addition : return add(int a, String b, String c);
case multiply : return multiply(int a, int b);
case substract : return substract(int a, int b);
Approach 1 : using polymorphism
方法一:使用多态
public interface Operation {
void performOperation(int a, int b);
}
Then fill a map with the available implementations:
然后用可用的实现填充地图:
Map<Key, Operation> actions = new HashMap<>();
actions.add(addition, new addOperation());
actions.add(multiply, new multiplyOperation());
actions.add(substract, new substractOperation());
Then I can refer the map when I need to perform a operation.
然后我可以在需要执行操作时参考地图。
The issues I have with this approach is that I am having to create a large number of classes / annonymous classes
我使用这种方法的问题是我必须创建大量的类/匿名类
Approach 2 : Using Enum
方法二:使用枚举
public enum MyKeyEnum {
ADDITION {
public void performOperation(int a, int b) {
// Perform addition
}
},
MULTIPLY {
public void performOperation(int a, int b) {
// Perform Multiplication
}
};
public abstract void performOperation(int counter, String dataMain, String dataSub);
}
This approach is actually better of the two but I saw another eaxmple in Java 8 and want use something like this
这种方法实际上是两者中更好的,但我在 Java 8 中看到了另一个 eaxmple 并且想要使用这样的东西
As all these are following a pattern I tried to use Functional Interface and Maps
由于所有这些都遵循我尝试使用功能接口和地图的模式
final static Map<String, Supplier<IAction>> map = new HashMap<>();
static {
map.put("add", Addition::new);
map.put("multiply", Multiply::new);
}
public static void main(String[] args) throws Exception {
Supplier<IAction> action = map.get("add");
System.out.println(action.get().performAction(10,10));
action = map.get("multiply");
System.out.println(action.get().performAction(10,10));
}
But this again has the disadvantages of the first approach so wanted to see if I can use lambdas like I used Enum implementation There is a partial function implementation provided in Java 8 which I wanted to utilize Example :
但这又具有第一种方法的缺点,所以想看看我是否可以像使用 Enum 实现一样使用 lambdas Java 8 中提供了一个部分函数实现,我想利用示例:
BiFunction<Integer, Integer, Integer> minus = (x, y) -> x - y;
Function<Integer, Integer> subtractor = partial(minus, 10);
System.out.println(subtractor.apply(4)); // 6
as BiFunction is accepting only 2 parameters I created a Trifuction like
因为 BiFunction 只接受 2 个参数,所以我创建了一个 Trifuction 像
@FunctionalInterface
interface TriFunction<T, U, V, R> {
R apply(T a, U b, V c);
}
public static <T, U, V, R> Function<V, R> partial(TriFunction<T, U, V, R> f, T x, U y) {
return (z) -> f.apply(x, y, z);
}
This will resolve the issue to an extent but I am not able to figure out how I can add this to the map and dynamically pass values
这将在一定程度上解决问题,但我无法弄清楚如何将其添加到地图并动态传递值
Map<String, TriFunction<String, Integer, Integer, Operation>> map
= new HashMap<>();
采纳答案by Flown
You are already there. If you've a method which has the same signature of your interface you can also pass it to your operation repository like:
你已经在那里了。如果您有一个与您的接口具有相同签名的方法,您还可以将其传递给您的操作存储库,例如:
Map<String, IntBinaryOperator> operations = new HashMap<>();
operations.put("add", Integer::sum);
operations.put("subtract", (a, b) -> a - b);
operations.put("multiply", (a, b) -> a * b);
//...
System.out.println(operations.get("multiply").applyAsInt(10, 20));
回答by avi.elkharrat
Thx for your question, as i stumbled on the exact same problem. I was looking for a way to eliminate if if if
or switch
blocks in my code for some time.
谢谢你的问题,因为我偶然发现了完全相同的问题。一段时间以来,我一直在寻找一种方法来消除if if if
或switch
阻止我的代码。
I opted for the Map
+ Supplier
approach, implemented within a factory, as in the following snippet:
我选择了在工厂内实现的Map
+Supplier
方法,如下面的代码片段所示:
public class OperatorFactory {
private final String supportedOperatorsRegex = "\+|\*|-";
private Map<String, Supplier<Operator>> supportedOperators = ImmutableMap.of(
"+", Addition::new, "*", Multiplication::new, "-", Subtraction::new, "ID", Identity::new
);
public Operator parseToOperator(String input) {
return supportedOperators.get(extractOperator(input)).get();
}
private String extractOperator(String input) {
Matcher matcher = Pattern.compile(supportedOperatorsRegex).matcher(input);
if (matcher.find()) return matcher.group();
if (input.matches("\d+")) return "ID";
throw new UnsupportedOperationException("unsupported operation: " + input);
}
}
I find this sollution closer to the Open / Close Principle (the O in SOLID principles):
我发现这个解决方案更接近开/关原则(SOLID 原则中的 O):
- Now, all i need to do to extend the functionalities is to add another operator class that implements some
Operator
interface that i have defined elsewhere, add it in thesupportedOperators
map and in theSupportedOperatorsRegex
without changing any of the business logic of theOperatorFactory
class. - Moreover, the client classes do not need to know what is happening in the
OperatorFactory
, and that is less coupling.
- 现在,为了扩展功能,我需要做的就是添加另一个运算符类,该类实现
Operator
我在别处定义的某些接口,将其添加到supportedOperators
地图中,SupportedOperatorsRegex
而不更改类的任何业务逻辑OperatorFactory
。 - 此外,客户端类不需要知道在 中发生了什么
OperatorFactory
,这减少了耦合。