改写if-else的几个思路
【摘要】 这种场景你有遇到过吗?
1. 卫语句提前return
假设有如下代码
if (condition) {
// do something
} else {
return xxx;
}
通过对判断条件取反,代码在逻辑表达上会更加清晰
if (!condition) {
return xxx;
}
// do something
2. 使用Optional简化if判空
2.1 简化1级判空
假设有如下代码
if (input != null) {
// return value 1
} else {
// return value 2
}
使用Optional后
return Optional.ofNullable(input).map(value1).orElse(value2);
2.2 简化多级判空
假设有如下代码
if (input != null && input.getUser() != null && input.getUser().getName() != null) {
// do action 1
} else {
// do action 2
}
使用Optional后
Optional.ofNullable(input)
.map(Input::getUser)
.map(User::getName)
.map(action1)
.orElse(action2);
对于没有else的场景,使用ifPresent即可
if (input != null && input.getUser() != null && input.getUser.getName() != null) {
// do action
}
Optional.ofNullable(input)
.map(Input::getUser)
.map(User::getName)
.ifPresent(action);
3. 策略模式
假设有如下代码:
if ("dog".equals(petType)) {
// 处理dog
} else if ("cat".equals(petType)) {
// 处理cat
} else if ("pig".equals(petType)) {
// 处理pig
} else if ("rabbit".equals(petType)) {
// 处理rabbit
} else {
throw new UnsupportedOperationException();
}
这就是不要根据不同的参数类型走不同的代码逻辑,这种场景很常见,他还会以switch-case的方式出现:
switch (petType) {
case "dog":
// 处理dog
break;
case "cat":
// 处理cat
break;
case "pig":
// 处理pig
break;
case "rabbit":
// 处理rabbit
break;
default:
throw new UnsupportedOperationException();
}
不同的代码逻辑就代表了不同的策略,我们可以通过如下几个方式改写。
3.1 多态
public interface Strategy {
void invoke(); // 处理各个逻辑
}
public class DogStrategy implements Strategy {
@Override
public void invoke() {
// 处理dog
}
}
public class CatStrategy implements Strategy {
@Override
public void invoke() {
// 处理cat
}
}
public class PigStrategy implements Strategy {
@Override
public void invoke() {
// 处理pig
}
}
public class RabbitStrategy implements Strategy {
@Override
public void invoke() {
// 处理rabbit
}
}
具体的策略对象可以放在一个Map中,优化后的实现类似如下
Strategy strategy = map.get(petType);
stratefy.invoke();
关于如何存放到Map中也两个可以参考的方式。
3.1.1 静态表
Map<String, Strategy> map = ImmutableMap.<String, Strategy>builder()
.put("dog", new DogStrategy())
.put("cat", new CatStrategy())
.put("pig", new PigStrategy())
.put("rabbit", new RabbitStrategy())
.build();
3.1.2 Spring托管下的动态注册
定义一个注册中心用于接受注册信息
public enum StrategyMapping {
INSTANCE;
private final Map<String, Class<? extends Strategy>> map = new ConcurrentHashMap<>();
public void register(String type, Class<? extends Strategy> clazz) {
map.put(type, clazz);
}
public Strategy getStrategy(String type) {
Class<? extends Strategy> clazz = map.get(type);
if (clazz == null) {
throw new UnregisteredException();
}
return SpringContextHolder.getBean(clazz);
}
}
将每个Strategy交由Spring管理,并在构造后注册
@Component
public class DogStrategy implements Strategy {
@PostConstruct
public void init() {
StrategyMapping.INSTANCE.register("dog", this.getClass());
}
@Override
public void invoke() {
// 处理dog
}
}
使用方式就变成了
Strategy strategy = StrategyMapping.INSTANCE.getStrategy(petType);
stratefy.invoke();
3.2 枚举
采用多态会额外产生很多策略类,如果我们已经预先将petType定义成了枚举,就会发现可以把Strategy中的invoke()方法放到枚举中,从而完成了一种映射关系。
public enum PetType {
DOG {
@Override
public void invoke() {
// 处理dog
}
},
CAT {
@Override
public void invoke() {
// 处理cat
}
},
PIG {
@Override
public void invoke() {
// 处理pig
}
},
RABBIT {
@Override
public void invoke() {
// 处理rabbit
}
};
public abstract void invoke();
}
这样在调用时的代码就类似如下:
PetType petType = PetType.valueOf(type.toUpperCase(Locale.ROOT));
petType.invoke();
3.3 函数式简化策略
同样面对多态会额外产生很多策略类的问题,除了枚举我们还可以使用函数式的方式来改写,这里有个前提最好是策略的内容不会过于复杂,不然在代码的可读性上会比较差
同样我们会有一个map静态表,不过map里面存放的是lambda
Map<String, Runnable> map = ImmutableMap.<String, Runnable>builder()
.put("dog", () -> {
// 处理dog
})
.put("cat", () -> {
// 处理cat
})
.put("pig", () -> {
// 处理pig
})
.put("rabbit", () -> {
// 处理rabbit
})
.build();
使用方式则变成了
Runnable task = map.get(petType);
task.run();
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)