怎样避免“if”嵌套

前几日在浏览stackoverflow网站时,偶然看到别人提的“How to avoid ‘if’ chains” 的问题,觉得这是一个编程人员在编程时很容易就碰到的问题,而且我自己在看一些源码时也遇到过这种编程方式,因此,对这个问题进行一点总结。

if嵌套的情况很多,下面列出一些情况,并给出了相对来说比较简洁的书写方式以供参考:

1、使用一个guard来使用代码变得平坦

a、代码如下:

if (ok)
{
    DoSomething();
}
else
{
    _log.Error("oops");
    return;
}

可以替换成:

if (!ok)
{
    _log.Error("oops");
    return;
}
DoSomething(); //notice how this is already farther to the left than the example above

b、代码如下:

ok = DoSomething1();
if (ok)
{
    ok = DoSomething2();
    if (ok)
    {
        ok = DoSomething3();
        if (!ok)
        {
            _log.Error("oops");  //Tip of the Arrow
            return;
        }
    }
    else
    {
       _log.Error("oops");
       return;
    }
}
else
{
    _log.Error("oops");
    return;
}

可以改写成:

ok = DoSomething1();
if (!ok)
{
    _log.Error("oops");
    return;
}
ok = DoSomething2();
if (!ok)
{
    _log.Error("oops");
    return;
}
ok = DoSomething3();
if (!ok)
{
    _log.Error("oops");
    return;
}
ok = DoSomething4();
if (!ok)
{
    _log.Error("oops");
    return;
}

2、最后有非条件执行代码的情况,伪代码如下:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}
executeThisFunctionInAnyCase();

函数executeStepX当且仅当前面的条件成立时才执行,而函数executeThisFunctionInAnyCase则在最后必需执行,而不管其它条件是否成立。

a、使用条件与(&&),利用条件短路的特性

if (executeStepA() && executeStepB() && executeStepC()){
    ...
}
executeThisFunctionInAnyCase();

b、使用finally

try
{
bool conditionA = executeStepA();
if (!conditionA) return;

bool conditionB = executeStepB();
if (!conditionB) return;

bool conditionC = executeStepC();
if (!conditionC) return;
}
finally
{
    executeThisFunctionInAnyCase();
}

c、将条件执行用一个函数包起来

void foo()
{
  bool conditionA = executeStepA();
  if (!conditionA) return;

  bool conditionB = executeStepB();
  if (!conditionB) return;

  bool conditionC = executeStepC();
  if (!conditionC) return;
}

void bar()
{
  foo();
  executeThisFunctionInAnyCase();
}

d、使用goto语句

int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanup;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    executeThisFunctionInAnyCase();
    return result;
}

e、利用条件的传递

bool condition = true; // using only one boolean variable
if (condition) condition = executeStepA();
if (condition) condition = executeStepB();
if (condition) condition = executeStepC();
...
executeThisFunctionInAnyCase();

f、使用异常

try {
    executeStepA();
    executeStepB();
    executeStepC();
}
catch (...) {
executeThisFunctionInAnyCase();
}

g、使用假循环

while(true)
{
    bool conditionA = executeStepA();
if (!conditionA) break;
bool conditionB = executeStepB();
if (!conditionB) break;
bool conditionC = executeStepC();
if (!conditionC) break;
    break;  //important
}
executeThisFunctionInAnyCase();

h、利用对象的生命周期

class MyContext
{
   ~MyContext()
   {
        executeThisFunctionInAnyCase();
   }
}

void MainMethod()
{
    MyContext myContext = new MyContext();

bool conditionA = executeStepA();
	if (!conditionA) return;

	bool conditionB = executeStepB();
	if (!conditionB) return;

	bool conditionC = executeStepC();
	if (!conditionC) return;

    //DoSomethingNoMatterWhat will be called when myContext goes out of scope
}

其中,最简单的是利用条件短路,而最复杂的是利用对象的生命周期。总结了这此情况和方法供大家参考,当然,可能还有很多其它的情况和处理方法,希望读者踊跃留言。

怎样避免“if”嵌套

时间: 2024-10-07 22:01:38

怎样避免“if”嵌套的相关文章

C#嵌套类

嵌套类顾名思义就是类或者结构中定义的类 class Container { class Nested { Nested() { } } } <1>嵌套类的默认访问权限是private ,可以指定为public,protected,private,internal,protected internal.<2>嵌套类型可以访问外部类(包裹嵌套类的类),如果要访问外部类型,要把外部类通过构造函数传进一个实例<3>嵌套类中只能访问外部类中的静态成员,不能直接访问外部类的非静态成

深度理解div+css布局嵌套盒子

1. 网页布局概述 网页布局的概念是把即将出现在网页中的所有元素进行定位,而CSS网页排版技术有别于传统的网页排版方法,它将页面首先在整体上使用<div>标记进行分块,然后对每个快进行CSS定位以及设置显示效果,最后在每个块中添加相应的内容.利用CSS排版方法更容易地控制页面每个元素的效果,更新也更容易,甚至页面的拓扑结构也可以通过修改相应的CSS属性来重新定位.  2. 盒子模型 盒子模型是CSS控制页面元素的一个重要概念,只有掌握了盒子模型,才能让CSS很好地控制页面上每一个元素,达到我们

4循环嵌套和方法

1 循环嵌套 循环嵌套(多重循环):一个循环结构中的循环体包含其他的循环结构. 任意两种循环结构都可以相互嵌套. for(表达式1;表达式2;表达式3){ for(表达式1;表达式2;表达式3){ } } 特点:外层循环执行1次,内层循环有可能执行多次. 只有当内层循环执行结束后,才会执行下次的外层循环. 示例1:打印3行8列的矩形矩形 public class TestLoop{ public static void main(String[] args){ //外层循环控制行数 for(in

ios嵌套H5页面,出现的小bug;

ios嵌套H5页面,点击数字时就会弹出打电话的功能:解决方法: 在head标签中添加: <meta name="format-detection" content="telephone=no"> ios嵌套H5页面,只要碰到页面,就会使input获取焦点,调取ios键盘,解决方法:在页面上添加js如下: $("body")[0].addEventListener("touchstart",function(){ d

JS中的循环结构、循环嵌套以及函数介绍

[循环结构的步骤]    *①声明循环变量    *②判断循环条件    *③执行循环体(while的{}中的所有代码)操作     *④更新循环变量    *     * 然后,循环执行②③④    *     *     * [JS中循环条件支持的数据类型]    * ①boolean:true 真     false   假    * ②string: 非空字符串为真       空字符串为假    * ③null/NaN/undefined:  全为假    * ④object:全为真 

Windwos Hyper-v嵌套虚拟化

现在微软的虚拟化越来越成熟,许多人也渐渐的开始研究微软的Hyper-V的虚拟化,但是苦于没有太多的电脑提供部署环境,再加上之前的windwos版本是不支持在虚拟机中安装Hyper-V,让大家头大. 现在的win10和win server 2016都已经支持嵌套虚拟化,也就是说可以在虚拟机中安装Hyper-V. 首先当然是安装Hyper-V,安装过程就省略了,相信大家肯定都知道. 安装完Hyper-V后新建一台虚拟机.在这里我建立一台名为test的虚拟机. 然后以管理员方式运行powershell

从ViewPager嵌套RecyclerView再嵌套RecyclerView看安卓事件分发机制

这两天伟大的PM下了一个需求,在一个竖滑列表里实现一个横向滑动的列表,没错,又是这种常见但是又经常被具有着强烈责任心和职业操守程序员所嗤之以鼻的效果,废话不多说,先上图: 实现的方式很多,因为项目中已经ViewPager+RV实现基本框架,所以现我也选择再添加一个RV实现相应的效果. 不过在写代码之前,先预估一下这个效果所有的坑. VP是横向滑动的,RV是竖向滑动的,那么现在再添加一个横向滑动的RV,肯定会有滑动冲突,主要表现在 VP和横向滑动RV 的冲突,因为两者都是横向滑动的,肯定有冲突,无

布局 - 嵌套

以面板为"画布",嵌套三层layout制作复杂的布局 <div class="easyui-panel" title="Complex Panel Layout" iconCls="icon-search" collapsible="true" style="padding:5px;width:500px;height:250px;"> <div class="

bash嵌套expect实现交换机的交互式登录实例

1. expect实现参数传递 1.1 实现 $argv 参数数组 expect脚本可以接受从bash传递过来的参数. 可以使用[lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个....参数 1.2 样例 cat telnet.exp #!/usr/bin/expect set host [lindex $argv 0] set passwd [lindex $argv 1] set passwden [lindex $argv 2] spawn telnet $h

rails嵌套资源的具名路由

假设有一个user模型,那么,users_path对应index的action,不需要参数,而对于user_path(),后面需要一个参数作为id,例如user_path(@user),表示@user对应的页面,具体含义与get/patch/delete有关 而edit_user_path(@user)和new_user_path与edit和new有关,create没有对应的具名路由. 如果给user嵌套了post资源,其实并没有太过复杂. index对应了user_posts_path(@us