If子句优化



我需要编写一个IF子句(我们使用的是Java 8)。相关变量为groupprivilegerolelevelclass。在某些情况下需要执行CCD_ 6。我用以下方式编写了alghoritm:

if (group == G1) {
if (privilege == P1) {
// Perform the action if a user has this particular privilege
perform_action_and_exit();
} else {
if (role == R1) {
if ((level <= 2 && class == C1) || (level == 1 && (class == C2 || class == C3))) {
perform_action_and_exit();
}
// Ignore other combinations of level and class
}
// Ignore other roles
}
} else {
// Perform the action for any group other than G1
perform_action_and_exit();
}

有没有更干净的方法来写这个条件?

谢谢。

在任何情况下,您都需要将操作与测试分离:

if (shouldPerform()) {
perform_action_and_exit();
}

有时,提前退出会使代码变得清晰:

boolean shouldPerform() {
if (group != G1) {
return true;
}
if (role != R1) {
return false;
}
if (level > 2) {
return false;
}
if (class == C1) {
return true;
}
if (level != 1) {
return false;
}
return class == C2 || class == C3;
}

有时,他们不会。只要看看这个,并决定你是否能第一眼就能理解它。你可能被告知类似的事情

  • 唯一的特权组是G1,其他组不受限制
  • 只有R1可以执行特权操作

然后这个早期退出正好映射到描述。

在任何情况下,我都不建议使用复杂的布尔表达式。任何跨越一两条线的东西都太难理解了。将方法或变量与简单表达式一起使用可以产生可读性更强的代码。


不要为这里的效率而烦恼当JVM内联方法并积极转换表达式时,很可能所有版本的条件都会导致同样快速的代码所以不要进行不必要的微优化,这就是机器的用途

此外,我敢打赌,perform_action_and_exit的执行时间至少比测试长四个数量级。测试可能需要几十纳秒(悲观地假设分支预测错误),而操作可能访问数据库,这意味着需要一些毫秒

您可以使用布尔代数重新组织和简化条件:

if (group != G1
|| privilege == P1
|| role == R1
&& (level <= 2 && class == C1
|| level == 1 && (class == C2 || class == C3))
) {
perform_action_and_exit();
}

首先,如果你真的需要违反Tell,不要问。

您的代码获得一些状态信息,然后根据这些信息做出决策。在一个好的OO模型中,只需告诉某个对象:"做正确的事情"。然后依靠多态性来确保doTheRightThing()对于当前状态是正确的。

如果你不想走这条路,你至少应该研究单层抽象原则。意思是:把你的条件表达式变成小的辅助方法,这样你的代码就可以读取:

if (isXCondition()) { 
doX();
}
if (isYCondition()) ...

以下是使代码更干净的重构示例,如果perform_action_and_exit()在整个代码中都是相同的方法,则可以对其进行进一步重构

if (group == G1) {
doG1Stuff();
} else {
// Perform the action for any group other than G1
perform_action_and_exit();
}
void doG1Stuff(){
if (privilege == P1) {
// Perform the action if a user has this particular privilege
perform_action_and_exit();
} else {
if (shouldActionBePerformed()) {
perform_action_and_exit();
}
}
}
boolean shouldActionBePerformed(){
return role == R1 && (level <= 2 && class == C1) || (level == 1 && (class == C2 || class == C3));
}

在业务逻辑中存在多个条件的情况下,声明性解决方案无疑更具可验证性和可跟踪性。嵌套if complex不是。声明您已经有了调用操作的最终标准。

然而,如果你不想使用表达式语言,java脚本API,JShell,那么你必须做这样的事情:

class Criteria {
Group group;
Privilege privilege;
Role role;
Level level;
}
class GuardedAction {
String caseName; // For tracability, an auditing name.
Predicate<Criteria> guard;
Runnable action;
}
List<GuardedAction> guardedActions;

请填写此列表,可能来自XML。为了追溯客户在旧日志中报告的"错误",版本号非常有用。

Criteria criteria = ...
for (GuardedAction ga : guardedActions) {
if (ga.guard.test(criteria)) {
System.out.println(ga.caseName);
Logger.log(Level.INFO(ga.toString()); // With a detailed toString.
ga.action.run();
break;
}
}

带有业务逻辑的嵌套if很难讨论。

代码看起来很乱,您已经重复了三次perform_action_and_exit();。想想单一责任。

//all the code should be replaced by this:
if(should_perform_action_and_exit()){
perform_action_and_exit();
}
....

然后为每个动作创建方法/类(更适合目的的方法)

boolean should_perform_action_and_exit(){
return groupCheck() || privilageCheck() || roleCheck();
}

现在是最后三种方法:

boolean groupCheck(){
return group != G1;
}
boolean privilageCheck(){
return privilege == P1;
}
boolean roleCheck(){
return (role == R1)  &&  ((level <= 2 && class == C1) || (level == 1 && (class == C2 || class == C3)));
}

上面的代码看起来可能更多,但可读性在以后会有所提高。

最新更新