精华内容
下载资源
问答
  • if-else 超过三层之后,代码的可读性就会大大降低。可以使用卫语句、策略模式、状态模式来改善代码结构。 具体方案如下: 卫语句 参考链接:https://blog.csdn.net/jw903/article/details/45506777 1.使用卫...

    if-else 超过三层之后,代码的可读性就会大大降低。可以使用卫语句、策略模式、状态模式来改善代码结构。

    具体方案如下:

    1. 卫语句
      参考链接:https://blog.csdn.net/jw903/article/details/45506777

      1.使用卫语句取代嵌套表达式

      函数中的条件逻辑使人难以看清正常的执行途径。使用卫语句表现所有特殊情况。

      动机:条件表达式通常有2种表现形式。第一:所有分支都属于正常行为。第二:条件表达式提供的答案中只有一种是正常行为,其他都是不常见的情况。

             这2类条件表达式有不同的用途。如果2条分支都是正常行为,就应该使用形如if…..else…..的条件表达式;如果某个条件极其罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回。这样的单独检查常常被称为“卫语句”。

             Replace Nested Conditional with Guard Clauses (以卫语句取代嵌套条件表达式)的精髓是:给某个分支以特别的重视。它告诉阅读者:这种情况很罕见,如果它真的发生了,请做一些必要的整理工作,然后退出。

             “每个函数只能有一个入口和一个出口”的观念,根深蒂固于某些程序员的脑海里。现今的编程语言都会强制保证每个函数只有一个入口,至于“单一出口”规则,其实不是那么有用。保持代码清晰才是最关键的:如果单一出口能使这个函数更清晰易读,那么就使用单一出口;否则就不必这么做。

      做法:1、对于每个检查,放进一个卫语句。卫语句要不就从函数返回,要不就抛出一个异常。

             2、每次将条件检查替换成卫语句后,编译并测试。如果所有卫语句都导致相同的结果,请使用 Consolidate Conditional Expression (合并条件表达式)。

      2.卫语句就是把复杂的条件表达式拆分成多个条件表达式,比如一个很复杂的表达式,嵌套了好几层的if - then-else语句,转换为多个if语句,实现它的逻辑,这多条的if语句就是卫语句.

      3有时候条件式可能出现在嵌套n次才能真正执行,其他分支只是简单报错返回的情况,对于这种情况,应该单独检查报错返回的分支,当条件为真时立即返回,这样的单独检查就是卫语句(guard clauses).卫语句可以把我们的视线从异常处理中解放出来,集中精力到正常处理的代码中。

      例如下列代码:


      void func(void)
      {
          if(IsWorkDay())
         {
             printf("Error,is work day");
         }
          else
         {
             if(IsWorkTime())
            {
              printf("Error ,is work time");
             }
             else
            {
                rest();
             }
          }
      }

      使用卫语句替换以后

      void func()

         if(IsWorkDay())
         {
            printf("Error,is work day");
            return;
         }
         if(IsWorkTime())
        {
            printf("Error,is work time");
            return ;
        }
       
        rest();
       
      }

       

    2. 策略模式
      参考链接:https://www.cnblogs.com/wkzhao/p/10229412.html

       

        什么是策略模式?其思想是针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。

           假如我们有一个根据不同用户类型返回不同折扣的方法,我们的实现可能是这样:

      复制代码

      import org.springframework.stereotype.Service;
      
      @Service
      public class CashService {
      
          public double cash(String type, double money) {
              if ("svip".equals(type)) {
                  return money * 0.75;
              } else if ("vip".equals(type)) {
                  return money * 0.9;
              } else {
                  return money;
              }
          }
      }

      复制代码

          现在我们各个类型的用户折扣耦合在一起,修改一个用户的折扣力度有可能会对其他类型用户造成影响。根据策略模式的思想,我们需要把折扣力度封装成具体的方法并面向接口编程。我们首先定义公共的接口DiscountService,编写其实现类,则我们改造后的代码可能如下所示:

           

      复制代码

      import com.study.designer.strategy.NormalDiscountStrategy;
      import com.study.designer.strategy.SvipDiscountStrategy;
      import com.study.designer.strategy.VipDiscountStrategy;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      @Service
      public class CashService {
      
      
          @Autowired
          private SvipDiscountStrategy svipDiscountStrategy;
      
          @Autowired
          private VipDiscountStrategy vipDiscountStrategy;
      
          @Autowired
          private NormalDiscountStrategy normalDiscountStrategy;
      
          public double cash(String type, double money) {
              if ("svip".equals(type)) {
                  return svipDiscountStrategy.getMoney(money);
              } else if ("vip".equals(type)) {
                  return vipDiscountStrategy.getMoney(money);
              } else {
                  return normalDiscountStrategy.getMoney(money);
              }
          }
      }

      复制代码

       

            可以看到,改造后的CashService中还存在许多if判断,我们需要消除这些if判断。我们可以在CashService初始化时就获取到所有的折扣策略,然后根据具体类型计算具体折扣。获取所有策略可以交由Spring来完成,改造后的代码如下所示:

      import com.study.designer.strategy.inf.DiscountStrategy;

      import org.springframework.stereotype.Service;

      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;

      @Service
      public class CashService {


          private Map<String, DiscountStrategy> strategyMap = new HashMap<>();


          public CashService(List<DiscountStrategy> strategies) {
              for (DiscountStrategy strategy : strategies) {
                  strategyMap.put(strategy.getType(), strategy);
              }
          }


          public double cash(String type, double money) {
              return strategyMap.get(type).getMoney(money);
          }
      }

       

       

    3. 状态模式
      参考链接:https://www.cnblogs.com/wkzhao/p/10229412.html

        本次LZ给各位介绍状态模式,之前在写设计模式的时候,引入了一些小故事,二十章职责连模式是故事版的最后一篇,之后还剩余四个设计模式,LZ会依照原生的方式去解释这几个设计模式,特别是原型模式和解释器模式,会包含一些其它的内容。

                     好了,接下来,我们先来看看状态模式的定义吧。

                     定义:(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

                     上述是百度百科中对状态模式的定义,定义很简单,只有一句话,请各位形象的去理解这句话,它说当状态改变时,这个对象的行为也会变,而看起来就像是这个类改变了一样。

                     这正是应验了我们那句话,有些人一旦发生过什么事以后,就像变了个人似的,这句话其实与状态模式有异曲同工之妙。

                     我们仔细体会一下定义当中的要点。

                     1、有一个对象,它是有状态的。

                     2、这个对象在状态不同的时候,行为不一样。

                     3、这些状态是可以切换的,而非毫无关系。

                     前两点比较好理解,第3点有时候容易给人比较迷惑的感觉,什么叫这些状态是可以切换的,而非毫无关系?

                     举个例子,比如一个人的状态,可以有很多,像生病和健康,这是两个状态,这是有关系并且可以转换的两个状态。再比如,睡觉、上班、休息,这也算是一组状态,这三个状态也是有关系的并且可以互相转换。

                     那如果把生病和休息这两个状态放在一起,就显得毫无意义了。所以这些状态应该是一组相关并且可互相切换的状态。

                     下面我们来看看状态模式的类图。

                        类图中包含三个角色。

                        Context:它就是那个含有状态的对象,它可以处理一些请求,这些请求最终产生的响应会与状态相关。

                        State:状态接口,它定义了每一个状态的行为集合,这些行为会在Context中得以使用。

                        ConcreteState:具体状态,实现相关行为的具体状态类。

                        如果针对刚才对于人的状态的例子来分析,那么人(Person)就是Context,状态接口依然是状态接口,而具体的状态类,则可以是睡觉,上班,休息,这一系列状态。

                        不过LZ也看过不少状态模式的文章和帖子,包括《大话设计模式》当中,都举的是有关人的状态的例子,所以这里给大家换个口味,我们换一个例子。

                        

                        我们来试着写一个DOTA的例子,最近貌似跟DOTA干上了,不为其他,就因为DOTA伴随了LZ四年的大学时光。

                        玩过的朋友都知道,DOTA里的英雄有很多状态,比如正常,眩晕,加速,减速等等。相信就算没有玩过DOTA的朋友们,在其它游戏里也能见到类似的情况。那么假设我们的DOTA没有使用状态模式,则我们的英雄类会非常复杂和难以维护,我们来看下,原始版的英雄类是怎样的。

      复制代码

      复制代码

      package com.state;
      
      
      //英雄类
      public class Hero {
          
          public static final int COMMON = 1;//正常状态
          
          public static final int SPEED_UP = 2;//加速状态
          
          public static final int SPEED_DOWN = 3;//减速状态
          
          public static final int SWIM = 4;//眩晕状态
          
          private int state = COMMON;//默认是正常状态
          
          private Thread runThread;//跑动线程
          
          //设置状态
          public void setState(int state) {
              this.state = state;
          }
          //停止跑动
          public void stopRun() {
              if (isRunning()) runThread.interrupt();
              System.out.println("--------------停止跑动---------------");
          }
          //开始跑动
          public void startRun() {
              if (isRunning()) {
                  return;
              }
              final Hero hero = this;
              runThread = new Thread(new Runnable() {
                  public void run() {
                      while (!runThread.isInterrupted()) {
                          try {
                              hero.run();
                          } catch (InterruptedException e) {
                              break;
                          }
                      }
                  }
              });
              System.out.println("--------------开始跑动---------------");
              runThread.start();
          }
          
          private boolean isRunning(){
              return runThread != null && !runThread.isInterrupted();
          }
          //英雄类开始奔跑
          private void run() throws InterruptedException{
              if (state == SPEED_UP) {
                  System.out.println("--------------加速跑动---------------");
                  Thread.sleep(4000);//假设加速持续4秒
                  state = COMMON;
                  System.out.println("------加速状态结束,变为正常状态------");
              }else if (state == SPEED_DOWN) {
                  System.out.println("--------------减速跑动---------------");
                  Thread.sleep(4000);//假设减速持续4秒
                  state = COMMON;
                  System.out.println("------减速状态结束,变为正常状态------");
              }else if (state == SWIM) {
                  System.out.println("--------------不能跑动---------------");
                  Thread.sleep(2000);//假设眩晕持续2秒
                  state = COMMON;
                  System.out.println("------眩晕状态结束,变为正常状态------");
              }else {
                  //正常跑动则不打印内容,否则会刷屏
              }
          }
      
      }

      复制代码

      复制代码

                      下面我们写一个客户端类,去试图让英雄在各种状态下奔跑一下。

      复制代码

      复制代码

      package com.state;
      
      public class Main {
      
          public static void main(String[] args) throws InterruptedException {
              Hero hero = new Hero();
              hero.startRun();
              hero.setState(Hero.SPEED_UP);
              Thread.sleep(5000);
              hero.setState(Hero.SPEED_DOWN);
              Thread.sleep(5000);
              hero.setState(Hero.SWIM);
              Thread.sleep(5000);
              hero.stopRun();
          }
      }

      复制代码

      复制代码


                      可以看到,我们的英雄在跑动过程中随着状态的改变,会以不同的状态进行跑动。

                      在上面原始的例子当中,我们的英雄类当中有明显的if else结构,我们再来看看百度百科中状态模式所解决的问题的描述。

                      状态模式解决的问题:状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

                      不用说,状态模式是可以解决我们上面的if else结构的,我们采用状态模式,利用多态的特性可以消除掉if else结构。这样所带来的好处就是可以大大的增加程序的可维护性与扩展性。

                      下面我们就使用状态模式对上面的例子进行改善,首先第一步,就是我们需要定义一个状态接口,这个接口就只有一个方法,就是run。

      复制代码

      复制代码

      package com.state;
      
      public interface RunState {
      
          void run(Hero hero);
          
      }

      复制代码

      复制代码

                      与状态模式类图不同的是,我们加入了一个参数Hero(Context),这样做的目的是为了具体的状态类当达到某一个条件的时候可以切换上下文的状态。下面列出四个具体的状态类,其实就是把if else拆掉放到这几个类的run方法中。

      复制代码

      复制代码

      package com.state;
      
      public class CommonState implements RunState{
      
          public void run(Hero hero) {
              //正常跑动则不打印内容,否则会刷屏
          }
      
      }

      复制代码

      复制代码

      复制代码

      复制代码

      package com.state;
      
      public class SpeedUpState implements RunState{
      
          public void run(Hero hero) {
              System.out.println("--------------加速跑动---------------");
              try {
                  Thread.sleep(4000);//假设加速持续4秒
              } catch (InterruptedException e) {}
              hero.setState(Hero.COMMON);
              System.out.println("------加速状态结束,变为正常状态------");
          }
          
      }

      复制代码

      复制代码

      复制代码

      复制代码

      package com.state;
      
      public class SpeedDownState implements RunState{
      
          public void run(Hero hero) {
              System.out.println("--------------减速跑动---------------");
              try {
                  Thread.sleep(4000);//假设减速持续4秒
              } catch (InterruptedException e) {}
              hero.setState(Hero.COMMON);
              System.out.println("------减速状态结束,变为正常状态------");
          }
      
      }

      复制代码

      复制代码

      复制代码

      复制代码

      package com.state;
      
      public class SwimState implements RunState{
      
          public void run(Hero hero) {
              System.out.println("--------------不能跑动---------------");
              try {
                  Thread.sleep(2000);//假设眩晕持续2秒
              } catch (InterruptedException e) {}
              hero.setState(Hero.COMMON);
              System.out.println("------眩晕状态结束,变为正常状态------");
          }
      
      }

      复制代码

      复制代码

                      这下我们的英雄类也要相应的改动一下,最主要的改动就是那些if else可以删掉了,如下。

      复制代码

      复制代码

      package com.state;
      
      
      //英雄类
      public class Hero {
          
          public static final RunState COMMON = new CommonState();//正常状态
          
          public static final RunState SPEED_UP = new SpeedUpState();//加速状态
          
          public static final RunState SPEED_DOWN = new SpeedDownState();//减速状态
          
          public static final RunState SWIM = new SwimState();//眩晕状态
          
          private RunState state = COMMON;//默认是正常状态
          
          private Thread runThread;//跑动线程
          
          //设置状态
          public void setState(RunState state) {
              this.state = state;
          }
          //停止跑动
          public void stopRun() {
              if (isRunning()) runThread.interrupt();
              System.out.println("--------------停止跑动---------------");
          }
          //开始跑动
          public void startRun() {
              if (isRunning()) {
                  return;
              }
              final Hero hero = this;
              runThread = new Thread(new Runnable() {
                  public void run() {
                      while (!runThread.isInterrupted()) {
                          state.run(hero);
                      }
                  }
              });
              System.out.println("--------------开始跑动---------------");
              runThread.start();
          }
          
          private boolean isRunning(){
              return runThread != null && !runThread.isInterrupted();
          }
      
      }

      复制代码

      复制代码

                      可以看到,现在我们的英雄类优雅了许多,我们使用刚才同样的客户端运行即可得到同样的结果。

                      对比我们的原始例子,现在我们使用状态模式之后,有几个明显的优点:

                      一、我们去掉了if else结构,使得代码的可维护性更强,不易出错,这个优点挺明显,如果试图让你更改跑动的方法,是刚才的一堆if else好改,还是分成了若干个具体的状态类好改呢?答案是显而易见的。

                      二、使用多态代替了条件判断,这样我们代码的扩展性更强,比如要增加一些状态,假设有加速20%,加速10%,减速10%等等等(这并不是虚构,DOTA当中是真实存在这些状态的),会非常的容易。                

                      三、状态是可以被共享的,这个在上面的例子当中有体现,看下Hero类当中的四个static final变量就知道了,因为状态类一般是没有自己的内部状态的,所有它只是一个具有行为的对象,因此是可以被共享的。
                      四、状态的转换更加简单安全,简单体现在状态的分割,因为我们把一堆if else分割成了若干个代码段分别放在几个具体的状态类当中,所以转换起来当然更简单,而且每次转换的时候我们只需要关注一个固定的状态到其他状态的转换。安全体现在类型安全,我们设置上下文的状态时,必须是状态接口的实现类,而不是原本的一个整数,这可以杜绝魔数以及不正确的状态码。

                      

                      状态模式适用于某一个对象的行为取决于该对象的状态,并且该对象的状态会在运行时转换,又或者有很多的if else判断,而这些判断只是因为状态不同而不断的切换行为。

                      上面的适用场景是很多状态模式的介绍中都提到的,下面我们就来看下刚才DOTA中,英雄例子的类图。

                        可以看到,这个类图与状态模式的标准类图是几乎一模一样的,只是多了一条状态接口到上下文的依赖线,而这个是根据实际需要添加的,而且一般情况下都是需要的。

                        状态模式也有它的缺点,不过它的缺点和大多数模式相似,有两点。

                        1、会增加的类的数量。

                        2、使系统的复杂性增加。
                        尽管状态模式有着这样的缺点,但是往往我们牺牲复杂性去换取的高可维护性和扩展性是相当值得的,除非增加了复杂性以后,对于后者的提升会乎其微。

                        状态模式在项目当中也算是较经常会碰到的一个设计模式,但是通常情况下,我们还是在看到if else的情况下,对项目进行重构时使用,又或者你十分确定要做的项目会朝着状态模式发展,一般情况下,还是不建议在项目的初期使用。

    展开全文
  • 一、if函数的规则 =IF(测试条件,真值,假值) 二、一层嵌套输出文本或数值 1.输出文本 =IF(E2=“理工”,“LG”,IF(E2=“文科”,“WK”,“JR”)) =IF(条件,真值,IF(条件,真值,...if函数嵌套的剥洋葱理论 ...

    一、if函数的规则

    =IF(测试条件,真值,假值)
    在这里插入图片描述

    二、一层嵌套输出文本或数值

    1.输出文本

    =IF(E2=“理工”,“LG”,IF(E2=“文科”,“WK”,“JR”))
    =IF(条件,真值,IF(条件,真值,价值))
    在这里插入图片描述

    2.输出数字

    =IF(E2=“理工”,B2+10,IF(E2=“文科”,B2+5,B2))在这里插入图片描述

    三、if函数嵌套的剥洋葱理论

    =IF(G2>=60,“第一批”,IF(G2>=40,“第二批”,“落榜”))
    从要求上看,第二批为60>X>=40,但是在if函数中这个式子是错误的。因为><属于同级符号,当处理完第一个>时,已经返回一个文本数据了,再对文本数据进行<运算,就会报错。
    所以选择G2>=40,因为在第一层的if测试条件中,得到的数据是已经过滤掉>=60的数据了
    在这里插入图片描述

    四、避免嵌套

    if函数最多七层嵌套,当用if复杂时 ,选用Vlookup

    =IF(H2=“第一批”,1000,0)+IF(H2=“第二批”,500,0)
    如果返回的是文字,0用空格替代,+用&替代
    在这里插入图片描述

    五、if函数与iserror嵌套

    =F18/E18
    因为数量栏有缺失值,所以结果错误,显示如下
    在这里插入图片描述
    解决办法,为了美观,不显示错误的值
    =IF(ISERROR(F18/E18)," ",F18/E18)
    在这里插入图片描述

    六、if函数与and(or)嵌套

    =IF(AND(A29=“男”,B29>=60),5000,0)
    只要是and函数里面的条件满足,就可以。
    and函数里面的条件不限个数,
    or函数同理
    在这里插入图片描述
    只有结果才决定写几个if函数
    例如:要求:60岁以上的男员工或者40岁以下的女员工给5000 。俩种结果有奖金或者没有奖金
    所以只需要1个if 函数

    =IF(OR(AND(A29=“男”,B29>=60),AND(A29=“女”,B29<=60)),5000,0)

    展开全文
  • Java的小本家2019-09-02 10:38:10 不知大家有没遇到过像“横放着的金字塔”一样的if else嵌套: ...我并没夸大其词,我是真的遇到...但if else一般不建议嵌套超过三层,如果一段代码存在过多的if else嵌套,代...

    Java的小本家 2019-09-02 10:38:10

    不知大家有没遇到过像“横放着的金字塔”一样的if else嵌套:

     

    减少该死的 if else 嵌套

     

     

    我并没夸大其词,我是真的遇到过了!嵌套6、7层,一个函数几百行,简!直!看!死!人!

    if else作为每种编程语言都不可或缺的条件语句,我们在编程时会大量的用到。但if else一般不建议嵌套超过三层,如果一段代码存在过多的if else嵌套,代码的可读性就会急速下降,后期维护难度也大大提高。所以,我们程序员都应该尽量避免过多的if else嵌套。下面将会谈谈我在工作中如何减少if else嵌套的。

    正文

    在谈我的方法之前,不妨先用个例子来说明if else嵌套过多的弊端。

    想象下一个简单分享的业务需求:支持分享链接、图片、文本和图文,分享结果回调给用户(为了不跑题,这里简略了业务,实际复杂得多)。当接手到这么一个业务时,是不是觉得很简单,稍动下脑就可以动手了:

    先定义分享的类型、分享Bean和分享回调类:

     

    减少该死的 if else 嵌套

     

     

    好了,然后在定义个分享接口,对每种类型分别进行分享就ok了:

     

    减少该死的 if else 嵌套

     

     

    到此,简单的分享模型就做出来了。有没问题?老实说,如果没什么追求的话,还真没什么问题,至少思路是清晰的。但一周后呢?一个月后呢?或者一年后呢?share方法的分支有15条,这意味着你每次回看代码得让自己的大脑变成微型的处理器,考虑15种情况。如果出现bug,你又得考虑15种情况,并15种情况都要测试下。再如果现在需要加多分享小视频功能,你又得添加多3个分支,还要改代码,一点都不“开放-闭合”。再再如果后面项目交接给他人跟进,他人又要把自己大脑变成处理器来想每个分支的作用,我敢肯定有百分之八十的人都会吐槽代码。

    我们程序员的脑力不应该花费在无止境的分支语句里的,应该专注于业务本身。所以我们很有必要避免写出多分支嵌套的语句。好的,我们来分析下上面的代码多分支的原因:

    1、空值判断

    2、业务判断

    3、状态判断

    几乎所有的业务都离不开这几个判断,从而导致if else嵌套过多。那是不是没办法解决了?答案肯定不是的。

    上面的代码我是用java写的,对于java程序员来说,空值判断简直使人很沮丧,让人身心疲惫。上面的代码每次回调都要判断一次listener是否为空,又要判断用户传入的ShareItem是否为空,还要判断ShareItem里面的字段是否为空......

    对于这种情况,我采用的方法很简单:接口分层。

    减少 if else 方法一:接口分层

    所谓接口分层指的是:把接口分为外部和内部接口,所有空值判断放在外部接口完成,只处理一次;而内部接口传入的变量由外部接口保证不为空,从而减少空值判断。

    来,看代码更加直观:

     

    减少该死的 if else 嵌套

     

     

    可以看到,上面的代码分为外部接口share和内部接口shareImpl,ShareItem和ShareListener的判断都放在share里完成,那么shareImpl就减少了if else的嵌套了,相当于把if else分摊了。这样一来,代码的可读性好很多,嵌套也不超过3层了。

    但可以看到,shareImpl里还是包含分享类型的判断,也即业务判断,我们都清楚产品经理的脑洞有多大了,分享的类型随时会改变或添加。嗯说到这里相信大家都想到用多态了。多态不但能应付业务改变的情况,也可以用来减少if else的嵌套。

    减少 if else 方法二:多态

    利用多态,每种业务单独处理,在接口不再做任何业务判断。把ShareItem抽象出来,作为基础类,然后针对每种业务各自实现其子类:

     

    减少该死的 if else 嵌套

     

     

    (注意:上面每个子类的构造方法还对每个字段做了空值处理,为空的话,赋值default,这样如果用户传了空值,在调试就会发现问题。)

    实现了多态后,分享接口的就简洁多了:

     

    减少该死的 if else 嵌套

     

     

    嘻嘻,怎样,内部接口一个if else都没了,是不是很酷~ 如果这个分享功能是自己App里面的功能,不是第三方SDK,到这里已经没问题了。但如果是第三方分享SDK的功能的话,这样暴露给用户的类增加了很多(各ShareItem的子类,相当于把if else抛给用户了),用户的接入成本提高,违背了“迪米特原则”了。

    处理这种情况也很简单,再次封装一层即可。把ShareItem的子类的访问权限降低,在暴露给用户的主类里定义几个方法,在内部帮助用户创建具体的分享类型,这样用户就无需知道具体的类了:

     

    减少该死的 if else 嵌套

     

     

    或者有人会说,这样用户也需额外了解多几个方法。我个人觉得让用户了解多几个方法好过了解多几个类,而已方法名一看就能知道意图,成本还是挺小,是可以接受的。

    其实这种情况,更多人想到的是使用工厂模式。嗯,工厂模式能解决这个问题(其实也需要用户额外了解多几个type类型),但工厂模式难免又引入分支,我们可以用Map消除分支。

    减少 if else 方法三:使用Map替代分支语句

    把所有分享类型预先缓存在Map里,那么就可以直接get获取具体类型,消除分支:

     

    减少该死的 if else 嵌套

     

     

    这种方式跟上面分为几个方法的方式各有利弊,看大家取舍了~

    写在最后

    讲到这里大家有没收获呢?总结下减少if else的方法:

    1、把接口分为外部和内部接口,所有空值判断放在外部接口完成;而内部接口传入的变量由外部接口保证不为空,从而减少空值判断。

    2、利用多态,把业务判断消除,各子类分别关注自己的实现,并实现子类的创建方法,避免用户了解过多的类。

    3、把分支状态信息预先缓存在Map里,直接get获取具体值,消除分支。

    好了,到此就介绍完了,希望大家以后写代码能注意,有则避之,无则加勉。希望大家写的代码越来越简洁~

    展开全文
  • 函数

    2017-12-03 15:25:31
    3.1 短小 函数第一规则短小 第二规则短小 if、else、while中的代码块语句应该只有一行;...函数不应大到可以容纳嵌套结构,缩进应该只有一或者两; 3.2 只做一件事 一件事是指在同一抽象上的事情;

    3.1 短小

    • 函数第一规则短小
    • 第二规则短小
    • if、else、while中的代码块语句应该只有一行;该行应该是一个函数调用语句,并且名称具有解释函数本身作用的功能;
    • 函数不应大到可以容纳嵌套结构,缩进层应该只有一层或者两层;

    3.2 只做一件事

    • 一件事是指在同一抽象层上的事情;

    3.3 每个函数一个抽象层级

    • 混乱的函数层级使得基础概念和细节不能清楚区分;
    • 混乱导致更加混乱;
    • 自顶向下的阅读顺序,函数的下面跟着位于下一层级的函数;

    3.4 switch语句

    • 使switch语句埋藏在抽象层级,去创建派生实体,实体抽象基类定义一般方法,并且由派生类实现自定义方法;
    • 单一权责原则:函数的改变仅有一个理由;
    • 开放闭合原则:对扩展开放,对修改闭合;

    3.5 使用描述性的名称

    • 函数越短小,功能越集中,就越便于取个好名字;
    • 长而具有描述性的名称比短而模糊的名称好,比长注释好;
    • 命名方式在同一模块中保持一致;

    3.6 函数参数

    • 最理想的函数参数是零,其次一,而后二,三参数避免
    • 函数通过参数输入,返回值输出,不太希望通过参数输出;

    3.6.1 一元函数的普遍形式

    三种情况:

    • 测试参数(输入一个,输出布尔值)
    • 对参数进行转换(输入一个,输出一个),即使要使用参数输出也应该转换为输出值
    • 事件函数(一个输入,没有输出)
    • 使用能区分三种功能的名称

    3.6.2 标识参数

    • 名称不清晰的形参会误导;
    • 形参为布尔值导致函数有两个方向,应分开;

    3.6.3 二元参数

    • 对于天生就有两个参数,当其存在自然的组合或者自然的顺序时,可以存在
    • assertEquals(expected,actual)这样的顺序是经过学习和约定的;
    • 将二元函数转换成一元函数,例如成为成员函数,或者成员变量;

    3.6.4 三元函数

    • 避免使用三元函数

    3.6.5 参数对象

    • 当函数需要传递多个有相互关系的参数时,应该封装成为一个类;

    3.6.6 参数列表

    3.6.7 动词与关键字

    • 给函数起一个好名字,能解释函数意图和参数顺序;
    • 函数和参数能够形成动名词队write(name)assertExpectedEqualsActual(expected,actual)

    3.7 无副作用

    • 坚持只做一件事原则;
    • 函数名词体现函数的全部功能;
    • 注意时序的耦合性,例如只该在初始化调用的地方仅在该处调用;
    • 对于输出参数,在面向对象的编程中,可以利用对象的this指针实现;

    3.8 分隔指令与询问

    • 函数做什么和回答什么要分开实现

    3.9 使用异常代替返回错误码

    • 当指令与询问混合时,会导致大量的语句嵌套;因为代码要求立即进行错误处理;但当使用异常时,可以将错误处理从主程序逻辑中分离出来;

    3.9.1 抽离Try/Catch代码块

    • 将Try代码块中的功能封装成一个函数,这样,此抽象层就只有错误处理功能,主要的逻辑处理在下一抽象层;错误处理和功能实现分隔;

    3.9.2 错误处理就是一件事

    • 函数只该做一件事,错误也是一件事;

    3.9.3 错误码

    • 返回错误码代表某处实现了某个枚举或者类;
    • 当修改该类或者枚举时,得重新编译和部署;
    • 但当使用异常时,新异常可以从异常类派生而来,无需重新编译(开放闭合原则)

    3.10 别重复自己

    • 重复时软件中一切邪恶的根源;

    3.11 结构化编程

    • 每个函数,函数中的每个代码块都应该只有一个入口和出口;因此只有一个return语句,循环中没有break和continue;绝对没有goto语句;
    • 以上规则吧不是绝对的,对于短小的函数可以使用return、break、continue,比单入单出原则更具有表达力;

    3.12 如何写出这样的代码

    • 先草稿,后打磨;
    展开全文
  • Scala之高阶函数嵌套函数两层嵌套三层嵌套形参是函数,返回是函数函数柯里化模式匹配样例类隐式参数 嵌套函数 两层嵌套 需求:输入一个字符串,判断这个字符串的长度跟5的大小分别输出两个数不同的结果 object ...
  • 在上一课python学习(二):列表嵌套中我们使用了三层嵌套,如果想再增加一层也是可以的,再加个for循环,if判断就行。但是,整个代码会显得臃肿,我们可以发现这些代码具有高度相似性,所以我们可以尝试创建一个...
  • 块内尽量调用“有意义签名”的函数,意味着函数不应该有嵌套结构,缩进不应该多与一或两。 3.只做一件事 函数中的语句,应该是一抽象使用几条指令处理或者使用下层抽象进行处理。一个只做一件事的函数,无法很...
  • Excel函数进阶学习

    2020-05-20 22:15:31
    还在不停的粘贴复制,还在不停的选择删除吗? 本课程是Excel进阶学习资料,可以让职场菜鸟Excel应用水平大幅提升,提高办公...第IF多层嵌套 对比Lookup数据分层 第四集 IS函数家族介绍 第五集 条件格式加函数
  • 一、概述 let 表达式,和 ‘ ?. ’运算符一起使用,很方便。不好描述,见下图 二、适用场景 ...一个对象的深层次嵌套属性需要拿来进行逻辑, 需要层层判断该属性是否为null 的... if (event.passiveType == Passiv...
  • Python 3基础教程9-函数

    2019-03-29 19:02:00
    本文介绍Python中的函数,主要了解如何定义一个函数,如何...再升级一下,如何求个数大小,这里有两个思路,多层嵌套if在一个函数里或者利用maxTwo()函数,这里介绍第二种,代码复用嘛。 转载于:https://www.c...
  • ​​​​​​​函数中需要用到if;elif;while;for等循环语句的地方,尽量不要嵌套过深,最好能控制在3以内。 原则二:参数个数不宜太多。 ​​​​​​​函数申明应该做到合理、简单、易于使用。除了函数名...
  • 实现步骤需要一嵌套函数。</li><li>可扩展性差,假如是要实现 multi(2)(3)(4)...(n) 这样的功能,那就得嵌套 n 层函数。</li></ul> 那么有没有更好的解决方案,答案是,使用函数式...
  • 声明工具函数: <pre><code> function getPropByPath(obj, path, strict) { let tempObj = obj; path = path.replace(/\[(\w+)\]/g, '.$1'); path = path.replace(/^\./, ''); ...
  • 作业要求及提示:级菜单 ''' 1.级菜单 2.可依次进入各子菜单 3.菜单能够回到上一级 4.用到知识点:字典、列表、多层循环、函数 ... 嵌套 if...if...if...else if elif else 循环:while 条件: ..... ...
  • Python 装饰器实现样例

    2017-09-12 21:21:21
    第一层传装饰器参数、第二层嵌套函数、第三层传被装饰函数的参数 二:三层返回 最里层返回func(*args)拿到参数,外层返回最里层函数,最外层返回次外层 ''' def dec(isnot = False): print 'call dec' if isnot...
  • for循环1.1 range函数1.2 使用range函数编写for循环1.3 巩固练习二、循环中的continue 与 break2.1 continue2.2 continue 与 if2.2.1 两种思路比较2.2.2 continue让代码更容易理解2.3 break、for...else3.1 语法...
  • 1、一段逻辑不要写的太长,如确实复杂可分几个函数调用实现 2、画面档名称和程式数组定义的名称保持一致 3、条件判断清晰明了,宁愿多用几个IF THEN END IF ...也尽量不要使用多层的IF THEN嵌套。同时做好备注
  • break:跳出当前循环,但是如果是嵌套循环,则只能跳出当前的这一循环,只有逐层break才能跳出所有循环;continue:跳出本次循环,开始下一次循环。return:跳出整个函数体,函数体后面的部分不再执行例如:public ...
  • 控制结构中的嵌套层数 变量个数(临时变量、全局变量) 同一变量的先后引用之间的代码行数(跨度) 变量生存的代码行数 圈复杂度计算方法 1:从1开始,一直往下通过程序; 2:一旦遇到以下关键字,加1(if、else if...
  • 以前在接手别人的项目的时候,经常碰到if else嵌套好几的情况,还有当同一页面上出现好多异步任务的时候,会出现大量的回调的嵌套,程序员往往分了很多的函数东一笔西一笔的,读起来非常困难。 而RxJava解决这类...
  • 带参数的装饰器

    2019-09-30 08:02:30
    当有很多函数都需要在某一个时间内需要装饰是,通过三层嵌套,可以实现对多个函数进行装饰。 import time FLAGE = False def timeer_out(flag): def timeer(func): def inner(*args,**kwargs): if flag...
  • 多个if排列版本二:if-else层层嵌套(套娃)版本if-elif版本四:while循环有限次数版本五:while循环无限次数猜数小游戏版本一版本二版本while循环版本四random模块randint()函数:生成随机数 分数分等级A、B...
  • C++ Primer 第

    2009-12-14 13:34:12
    5.3 if语句 175 5.4 switch语句 183 5.5 for循环语句 190 5.6 while循环 194 5.7 do while 196 5.8 break语句 198 5.9 continue语句 199 5.10 goto语句 199 5.11 链表例子 201 第6章 抽象容器类型 226 ...
  • C++ Primer (第版)(高清PDF中文版)

    热门讨论 2011-06-07 09:18:21
    5.3 if语句 175 5.4 switch语句 183 5.5 for循环语句 190 5.6 while循环 194 5.7 do while 196 5.8 break语句 198 5.9 continue语句 199 5.10 goto语句 199 5.11 链表例子 201 第6章 抽象容器类型 226 6.1 我们的...
  • 一个函数方法 50 60对if else 还来个两三层嵌套,完了这个方法只是提供的一个完整查询中的一个子句,要两三个这样的方法才凑个一个完整的查询,这个查询只对应界面上,二三十个条件组合中的一种情况,我人裂开了 ...
  • 引言:promise的出现就是为了解决...回调地狱:函数作为参数层层嵌套 开始学习: 这里申明函数No1No2No3 var status = 1; function No1(resolve,reject){ if(status ==1){ console.log('这是第一个函数')...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 142
精华内容 56
关键字:

if函数三层嵌套