我有编程经验,但在软件开发方面没有太多经验。我目前正在为我工作的公司编写一个软件,我开始挑战自己代码的可读性。
我想知道这是否是嵌入 if 语句的“有效”替代方案,或者是否有更好的我可以使用。
假设我有以下方法:
public void someMethod()
{
if (some condition)
{
if (some condition 2)
{
if (some condition 3)
{
// ...etc all the way until:
doSomething();
}
else
{
System.err.println("Specific Condition 3 Error");
}
}
else
{
System.err.println("Specific Condition 2 Error");
}
}
else
{
System.err.println("Specific Condition 1 Error");
}
}
现在我应该指出的第一件事是,在这种情况下,将条件(与 &&)组合起来是不可能的,因为每个条件都有一个我想报告的独特错误,如果我将它们组合起来,我就不会能够做到这一点(或者我会吗?)。在有人尖叫“切换声明!”之前我应该指出的第二件事在我看来,并非所有这些条件都可以通过 switch 语句来处理;有些是对象特定的方法调用,有些是整数比较等。
也就是说,以下是使上述代码更具可读性的有效方法,还是有更好的方法?
public void someMethod()
{
if (!some condition)
{
System.err.println("Specific Condition 1 Error");
return;
}
if (!some condition 2)
{
System.err.println("Specific Condition 2 Error");
return;
}
if (!some condition 3)
{
System.err.println("Specific Condition 3 Error");
return;
}
doSomething();
}
所以基本上,我们不是检查条件并在 else 块中报告错误,而是检查条件的逆并在为真时返回。结果应该是一样的,但是有没有更好的方法来处理这个问题?
你的第二种方法相当不错。如果您想要一些更巴洛克风格的东西,您可以将您的条件移至 Callable 对象中。每个对象还可以提供一种处理错误的方法。这使您可以编写任意长的一系列测试,而不会牺牲功能。
class Test {
private final Callable<Boolean> test;
private final Runnable errorHandler;
public Test(Callable<Boolean> test, Runnable handler) {
this.test = test;
errorHandler = handler;
}
public boolean runTest() {
if (test.call()) {
return true;
}
errorHandler.run();
return false;
}
}
然后您可以按如下方式组织代码:
ArrayList<Test> tests;
public void someMethod() {
for (Test test : tests) {
if (!test.runTest()) {
return;
}
}
doSomething();
}
编辑
这是上述内容的更通用版本。它应该可以处理几乎所有这种类型的情况。
public class Condition {
private final Callable<Boolean> test;
private final Runnable passHandler;
private final Runnable failHandler;
public Condition(Callable<Boolean> test,
Runnable passHandler, Runnable failHandler)
{
this.test = test;
this.passHandler = passHandler;
this.failHandler = failHandler;
}
public boolean check() {
if (test.call()) {
if (passHandler != null) {
passHandler.run();
}
return true;
}
if (errorHandler != null) {
errorHandler.run();
}
return false;
}
}
public class ConditionalAction {
private final ArrayList<Condition> conditions;
private final Runnable action;
public ConditionalAction(ArrayList<Condition> conditions,
Runnable action)
{
this.conditions = conditions;
this.action = action;
}
public boolean attemptAction() {
for (Condition condition : conditions) {
if (!condition.check()) {
return false;
}
}
action.run();
return true;
}
}
人们可能会想添加某种可以传递以共享信息或收集结果的通用数据。我不建议这样做,而是建议在实现条件和操作的对象内实现此类数据共享,并保持此结构不变。
如果我特别迂腐,我会使用这样的东西。
boolean c1, c2, c3;
public void someMethod() {
boolean ok = true;
String err = "";
if (ok && !(ok &= c1)) {
err = "Specific Condition 1 Error";
}
if (ok && !(ok &= c2)) {
err = "Specific Condition 2 Error";
}
if (ok && !(ok &= c3)) {
err = "Specific Condition 3 Error";
}
if ( ok ) {
doSomething();
} else {
System.out.print(err);
}
}
您现在是单出口且平坦。
已添加
如果 &= 对您来说很难,请使用类似以下内容:
if (ok && !c3) {
err = "Specific Condition 3 Error";
ok = false;
}
我会把它写成
if (failing condition) {
System.err.println("Specific Condition 1 Error");
} else {
somethingExpensiveCondition2and3Dependon();
if (failing condition 2)
System.err.println("Specific Condition 2 Error");
else if (failing condition 3)
System.err.println("Specific Condition 3 Error");
else
doSomething();
}
对于这种情况,这与您将得到的一样干净,因为您对每个条件都有自定义标准和自定义响应。
您本质上所做的是在调用
doSomething()
方法之前验证一些条件。我会将验证提取到一个单独的方法中。
public void someMethod() {
if (isValid()) {
doSomething();
}
}
private boolean isValid() {
if (!condition1) {
System.err.println("Specific Condition 1 Error");
return false;
}
if (!condition2) {
System.err.println("Specific Condition 2 Error");
return false;
}
if (!condition3) {
System.err.println("Specific Condition 3 Error");
return false;
}
return true;
}
不,这就是 Java 中的内容。如果您有太多这些,则可能表明您应该进行一些重构,甚至可能重新考虑您的算法 - 尝试稍微简化它可能是值得的,因为否则您将返回到中的代码几个月了,想知道为什么
a + b + c + d = e
但是a + b' + c + d = zebra
您拥有的第二个选项是更具可读性的。虽然通常不建议使用多个返回值,但将它们全部放在代码的开头是很清楚的(这并不是说它们分散在整个方法中)。另一方面,嵌套的 if 很难遵循和理解。
如果这些
if
测试对对象的字段强制执行规则,例如“年龄不能为负数”和“姓名长度必须至少有三个字符”,那么您可以考虑使用 Jakarta Validation。以前称为 Bean 验证。
使用注释将规则附加到字段。
@Min( 0 )
int countGuests
雅加达验证提供了几条规则。您也可以编写自己的规则。