我经常遇到必须执行大量检查的代码,并且在真正做任何事情之前最终会缩进至少五到六个级别。我想知道有哪些替代方案。
下面我发布了一个我正在谈论的例子(这不是实际的生产代码,只是我想到的东西)。
public String myFunc(SomeClass input)
{
Object output = null;
if(input != null)
{
SomeClass2 obj2 = input.getSomeClass2();
if(obj2 != null)
{
SomeClass3 obj3 = obj2.getSomeClass3();
if(obj3 != null && !BAD_OBJECT.equals(obj3.getSomeProperty()))
{
SomeClass4 = obj3.getSomeClass4();
if(obj4 != null)
{
int myVal = obj4.getSomeValue();
if(BAD_VALUE != myVal)
{
String message = this.getMessage(myVal);
if(MIN_VALUE <= message.length() &&
message.length() <= MAX_VALUE)
{
//now actually do stuff!
message = result_of_stuff_actually_done;
}
}
}
}
}
}
return output;
}
答案 0 :(得分:16)
请参阅Flattening Arrow Code寻求帮助。
- 用防护装置替换条件 条款。
- 将条件块分解为 单独的功能。
- 将否定支票转换为 积极的检查。
醇>
答案 1 :(得分:8)
早退:
if (input == null) {
return output;
}
答案 2 :(得分:7)
请永远不要那样编码(除非你维护自己的代码)
我必须维护这样的代码,并且像Charles_Bronsonn电影一样糟糕(有些人喜欢那些电影)
这种代码通常来自程序语言,例如C(C程序:P)无论如何。
这就是ObjectOrientedProgrammng成为主流的原因。它允许您创建对象并向其添加状态。使用该状态创建操作。他们不仅是财产持有人。
我知道你构成了那个场景,但大多数时候所有这些条件都是业务规则!! 。大多数情况下,这些规则会更改,如果原始开发人员不再在那里(或者已经过了几个月),那么修改该代码将没有可行的方法。这些规则难以阅读。而且很多痛苦来自于此。
1。)使用私有成员变量(AKA属性,属性,实例变量等)保持对象的状态INSIDE对象
2。)将方法设为私有(这是访问级别的用途),这样任何人都不能错误地调用它们并将程序放在NullPointerException域中。
3。)创建定义条件的方法。这就是他们所谓的自我记录代码
所以而不是
// validates the user has amount
if( amount > other && that != var || startsAligned() != false ) {
}
创建方法
if( isValidAmount() ) {
}
private boolean isValidAmount() {
return ( amount > other && that != var || startsAligned() != false );
}
我知道它看起来很冗长,但允许人类能够阅读代码。编译器不关心可读性。
那么你用这种方法看起来会怎么样呢?
喜欢这个。
// these are business rules
// then it should be clear that those rules are
// and what they do.
// internal state of the object.
private SomeClass2 obj2;
private SomeClass3 obj3;
private SomeClass4 obj4;
//public String myFunc( SomeClass input ) {
public String myComplicatedValidation( SomeClass input ) {
this.input = input;
if ( isValidInput() &&
isRuleTwoReady() &&
isRuleTreeDifferentOf( BAD_OBJECT ) &&
isRuleFourDifferentOf( BAD_VALUE ) &&
isMessageLengthInRenge( MIN_VALUE , MAX_VALUE ) ) {
message = resultOfStuffActuallyDone();
}
}
// These method names are self explaining what they do.
private final boolean isValidInput() {
return this.input != null;
}
private final boolean isRuleTwoReady() {
obj2 = input.getSomeClass2();
return obj2 != null ;
}
private final boolean isRuleTreeDifferentOf( Object badObject ) {
obj3 = obj2.getSomeClass3();
return obj3 != null && !badObject.equals( obj3.getSomeProperty() );
}
private final boolean isRuleFourDifferentOf( int badValue ) {
obj4 = obj3.getSomeClass4();
return obj4 != null && obj4.getSomeValue() != badValue;
}
private final boolean isMessageLengthInRenge( int min, int max ) {
String message = getMessage( obj4.getSomeValue() );
int length = message.length();
return length >= min && length <= max;
}
我知道,它看起来更像编码。但想想这个。规则几乎是人类可读的
if ( isValidInput() &&
isRuleTwoReady() &&
isRuleTreeDifferentOf( BAD_OBJECT ) &&
isRuleFourDifferentOf( BAD_VALUE ) &&
isMessageLengthInRenge( MIN_VALUE , MAX_VALUE ) ) {
message = resultOfStuffActuallyDone();
}
几乎可以读作
if is valid input
and rule two is ready
and rule three is not BAD OBJECT
and rule four is no BAD_VALUE
and the message length is in range
通过保持规则变小,编码员可以很容易地理解它们而不是害怕刹车。
了解更多内容答案 3 :(得分:2)
是的,您可以按如下方式删除缩进:
基本上按顺序进行检查,并与失败而不是成功进行比较。 它删除了嵌套并使其更容易跟踪(IMO)。
public String myFunc(SomeClass input)
{
Object output = null;
if (input == null)
{
return null;
}
SomeClass2 obj2 = input.getSomeClass2();
if (obj2 == null)
{
return null;
}
SomeClass3 obj3 = obj2.getSomeClass3();
if (obj3 == null || BAD_OBJECT.equals(obj3.getSomeProperty()))
{
return null;
}
SomeClass4 = obj3.getSomeClass4();
if (obj4 == null)
{
return null;
}
int myVal = obj4.getSomeValue();
if (BAD_VALUE == myVal)
{
return null;
}
String message = this.getMessage(myVal);
if (MIN_VALUE <= message.length() &&
message.length() <= MAX_VALUE)
{
//now actually do stuff!
message = result_of_stuff_actually_done;
}
return output;
}
答案 4 :(得分:1)
你可以使用guard子句来摆脱一些嵌套。
public String myFunc(SomeClass input)
{
Object output = null;
if(input == null) return "";
SomeClass2 obj2 = input.getSomeClass2();
if(obj2 == null) return "";
SomeClass3 obj3 = obj2.getSomeClass3();
if(obj3 == null || BAD_OBJECT.equals(obj3.getSomeProperty()))
{
return "";
}
SomeClass4 = obj3.getSomeClass4();
if(obj4 == null) return "";
int myVal = obj4.getSomeValue();
if(BAD_VALUE == myVal) return "";
String message = this.getMessage(myVal);
if(MIN_VALUE <= message.length() &&
message.length() <= MAX_VALUE)
{
//now actually do stuff!
message = result_of_stuff_actually_done;
}
return output;
}
更改我用来说明指向抛出描述性异常的语句的所有return "";
语句。
答案 5 :(得分:1)
如果您不需要处理停止,请不要嵌入。
例如,你可以这样做:
if(input == null && input.getSomeClass2() == null && ...)
return null;
// Do what you want.
假设您正在使用Java之类的语言来命令条件语。
或者你可以:
if(input == null && input.getSomeClass2() == null)
return null;
SomeClass2 obj2 = input.getSomeClass2();
if(obj2 == null)
return null;
...
// Do what you want.
对于更复杂的案例。
如果您不需要处理,我们的想法是从方法返回。嵌入大型嵌套if几乎不可能阅读。
答案 6 :(得分:0)
如果它只是一个可读性问题,你可以通过将嵌套移动到另一个方法来使其更清晰。如果您愿意,还可以转换为警卫风格。
public String myFunc(SomeClass input)
{
Object output = null;
if (inputIsValid(input))
{
//now actually do stuff!
message = result_of_stuff_actually_done;
}
return output;
}
private bool inputIsValid(SomeClass input)
{
// *****************************************
// convert these to guard style if you like
// *****************************************
if(input != null)
{
SomeClass2 obj2 = input.getSomeClass2();
if(obj2 != null)
{
SomeClass3 obj3 = obj2.getSomeClass3();
if(obj3 != null && !BAD_OBJECT.equals(obj3.getSomeProperty()))
{
SomeClass4 = obj3.getSomeClass4();
if(obj4 != null)
{
int myVal = obj4.getSomeValue();
if(BAD_VALUE != myVal)
{
String message = this.getMessage(myVal);
if(MIN_VALUE <= message.length() &&
message.length() <= MAX_VALUE)
{
return true;
}
}
}
}
}
}
return false;
}