3

我正在用 Java 开发一个 BlackBerry 应用程序,并且我有一个 Options 类,其中存储了所有用户设置。问题是我需要检查一些条件才能知道如何做出反应。随着我不断添加更多功能,向用户显示更多 GUI 选项,更多设置存储在 Options 类中,需要检查更多条件。

以下面的代码为例:

private void doCallMonitoring(int callId){
    /*This is the part that I want to avoid. Having
      multiple nested ifs. Here's just two conditions
      but as I add more, it will get unmantainable
      very quickly.*/
    if(Options.isActive().booleanValue()){
        callTime = new Timer();
        TimerTask callTimeTask = new TimerTask(){
            public void run(){
                callTimeSeconds++;
        if((callTimeSeconds == Options.getSoftLimit().intValue()) && (Phone.getActiveCall().getStatus() == PhoneCall.STATUS_CONNECTED)){
                    injectDTMFTone(Phone.getActiveCall());
        }else if((callTimeSeconds >= Options.getHardLimit().intValue()) && (Phone.getActiveCall().getStatus() == PhoneCall.STATUS_CONNECTED)){
                    injectEndCall();
                }
             }
        };     
        callTime.schedule(callTimeTask, 0,1000);
    }else{
    System.out.println("Service not active");
    }
}

我希望它如何工作是通过一次调用来验证所有选项,并从那里确定行动的诅咒。我怎样才能实现这样的设计?

4

4 回答 4

4

另一种选择是制作方法,例如injectDMTFTone()检查他们是否要处理该条件,并根据是否已处理返回真或假。

例如:

public void run() {
    callTimeSeconds++;
    do {
        if (handleInjectDMTFTone())
            break;
        if (handleInjectEndCall())
            break;
    } while(false);

    callTime.schedule(callTimeTask, 0,1000);
}

boolean handleInjectDMTFTone() {
    if ((callTimeSeconds != Options.getSoftLimit().intValue()) ||
        (Phone.getActiveCall().getStatus() != PhoneCall.STATUS_CONNECTED))
        return false;

    injectDTMFTone(Phone.getActiveCall());
    return true;
}

boolean handleInjectEndCall() {

    if ((callTimeSeconds < Options.getHardLimit().intValue()) ||
        (Phone.getActiveCall().getStatus() != PhoneCall.STATUS_CONNECTED))
        return false;

    injectEndCall();
    return true;
}

当然,您只需在这些方法中内联该逻辑,而不是调用另一个injectDMTFTone()方法或方法。injectEndCall()通过这种方式,您将如何以及何时处理这些条件的所有逻辑组合在同一个地方。

这是我最喜欢的模式之一;尽可能使用if靠近方法顶部的语句来消除条件并返回。该方法的其余部分没有缩进很多级别,并且易于阅读。

您可以通过创建所有实现相同接口并位于处理程序存储库中的对象来进一步扩展它,您的run方法可以迭代这些处理程序以查看哪个将处理它。这对您的情况可能会也可能不会过分杀伤力。

于 2009-03-06T23:26:47.047 回答
2

您可以使用“提取方法”重构并将所有这些检查变成一个“可读”条件。

看到这个相关的答案有点冗长,但关键是要替换这样的结构:

       }else if((callTimeSeconds >= Options.getHardLimit().intValue()) && (Phone.getActiveCall().getStatus() == PhoneCall.STATUS_CONNECTED)){
                injectEndCall();
            }
         }

对于这样的事情:

       ....
       }else if(shouldInjectEndCall() ){
                injectEndCall();
            }
         }
       ...

请记住,对象确实具有状态,并且可能使用其他对象来帮助它们完成工作。

于 2009-03-06T23:10:53.873 回答
1

其他选择是做某种“用多态性替换条件”。

尽管看起来只是编写更多代码,但您可以用“验证器”对象替换所有这些规则,并将所有验证放在某个数组中并循环它们。

像这样的临时代码。

  private void doCallMonitoring(int callId){
     // Iterate the valiators and take action if needed. 

      for( Validation validation : validationRules ) { 
          if( validation.succeed() ) { 
              validation.takeAction();
          }
      }
   }

你像这样实现它们:

abstract class Validation { 

      public boolean suceed();
      public void takeAction();
}

class InjectDTMFToneValidation extends Validation { 
    public boolean suceed() { 
        return (callTimeSeconds == Options.getSoftLimit().intValue()) 
               && (Phone.getActiveCall().getStatus() == PhoneCall.STATUS_CONNECTED)
     }
     public void takeAction() { 
         injectDTMFTone(Phone.getActiveCall());
     }
}

class InjectEndCallValidation extends Validation { 
    public boolean suceed() { 
        return (callTimeSeconds >= Options.getHardLimit().intValue()) 
                && (Phone.getActiveCall().getStatus() == PhoneCall.STATUS_CONNECTED)
     }
     public void takeAction() { 
         injectEndCall();
     }
}

最后将它们安装在列表中:

private List<Validation> validationRules = new ArrayList<Validation>();{
   validationrules.add( new InjectDTMFToneValidation() );
   validationrules.add( new InjectEndCallValidation () );
   ...
   ...
}

这里的想法是将逻辑移动到子类。当然,您将获得更好的结构,并且可能会成功,并且takeAction可以被替换为其他更有意义的方法,目的是从它所在的位置提取验证。

变得更抽象了?.. 是的。

顺便说一句,我为什么要使用 Options 和 Phone 类来调用它们的静态方法而不是使用实例?

于 2009-03-06T23:26:01.980 回答
1

所有这些答案可能都是更好的面向对象的答案。这一次,我将寻求快速而肮脏的答案。

我真的很喜欢通过反转它们来简化复杂的嵌套 if。

if(!Options.isActive().booleanValue()) {
    System.out.println("Service not active");
    return;
}
the rest...

我知道有些人不喜欢中间方法返回,但是当您验证对我来说一直是一个很棒的模式的进入条件时,我从不后悔使用它。

它确实简化了您的方法的外观。

如果你编写的方法比屏幕长,不要这样做或写一个大的注释指出它——太容易丢失返回语句而忘记你做了。更好的是,不要编写比屏幕更长的方法。

于 2009-03-07T00:19:26.453 回答