Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Refactoring 这种控制流动结构的做法是否良好?_Refactoring_Control Flow - Fatal编程技术网

Refactoring 这种控制流动结构的做法是否良好?

Refactoring 这种控制流动结构的做法是否良好?,refactoring,control-flow,Refactoring,Control Flow,我想重新编写一个嵌套if语句过多的方法 我提出了这一方法,希望得到您的意见: public void MyMethod() { bool hasFailed = false; try { GetNewOrders(out hasFailed); if(!hasFailed) CheckInventory(out hasFailed); if(!hasFailed) PreOrder(out has

我想重新编写一个嵌套
if
语句过多的方法

我提出了这一方法,希望得到您的意见:

public void MyMethod()
{
   bool hasFailed = false;

   try
   {
      GetNewOrders(out hasFailed);

      if(!hasFailed)
          CheckInventory(out hasFailed);

      if(!hasFailed)
          PreOrder(out hasFailed);              

      // etc
   }
   catch(Exception ex)
   {
   }
   finally
   {
      if(hasFailed)
      {
           // do something
      }
   }
}

我觉得这个不太好。hasFailed变量的使用真的不好。如果GetNewOrders因异常而失败,例如,您将以hasFailed=false结束catch块


与这里的其他答案相反,我相信布尔“hasfiled”可能有合法的用法,但并不例外。但我真的不认为应该将这样的条件混合到异常处理程序中

不太可能。如果“catch”块捕捉到错误,您的方法应该引发异常。

我做过类似的事情,但没有异常处理:

BOOL ok = CallSomeFunction();
if( ok ) ok = CallSomeOtherFunction();
if( ok ) ok = CallYetAnotherFunction();
if( ok ) ok = WowThatsALotOfFunctions();
if( !ok ) {
    // handle failure
}
或者如果你想变得聪明:

BOOL ok = CallSomeFunction();
ok &= CallSomeOtherFunction();
ok &= CallYetAnotherFunction();
...

如果仍然使用异常,为什么需要
hasfiled
变量?

而不评论try/catch内容,因为我真的不知道那里发生了什么,我会更改它,使被调用的方法返回true/false以获得成功,然后根据布尔短路来检查它们,以避免在前面的方法失败时调用后面的方法

public void MyMethod()
{
    bool success = false;
    try
    {
         success = GetNewOrders()
                   && CheckInventory()
                   && PreOrder();
         // etc
    }
    catch(Exception ex)   {   }
    finally
    {
        if(!success)
        {
        }
    }
}

我知道我可能会重复一些帖子:
还有什么问题?您还可以使用惰性求值(
a()&&b()
)来链接方法,但这取决于状态作为返回值给出,无论如何,返回值的可读性更高


我不同意你应该引发异常的说法,因为如果程序出现错误或者程序因为操作而进入异常状态,那么应该引发异常。异常不是业务逻辑。

我会这样做:

public void MyMethod()
{
bool success = false;   
try
   {

      GetNewOrders(); // throw GetNewOrdersFailedException    
      CheckInventory(); // throw CheckInventoryFailedException
      PreOrder(); // throw PreOrderFailedException  
      success = true;            
   }
   catch( GetNewOrdersFailedException e)
   {
     // Fix it or rollback
   }
   catch( CheckInventoryFailedException e)
   {
     // Fix it or rollback
   }
   catch( PreOrderFailedException e)
   {
     // Fix it or rollback
   }
   finally
   {
      //release resources;
   }
}
扩展异常非常简单


public NewExecption:BaseExceptionType{}

据我所知,这是一个级联步骤的示例,其中,如果第一个和第一个及第二个都有效,则将执行第二个和第三个步骤,即返回hasfiled==false

使用模板方法和Decorator设计模式可以使代码更加优雅

您需要一个接口、具体实现、抽象类和抽象类的几个子类

public interface Validator {
    public boolean isValid();
}

public class GetNewOrders implements Validator {
    public boolean isValid() {
       // same code as your GetNewOrders method
    }
}

public abstract class AbstractValidator implements Validator {
    private final Validator validator;

    public AbstractValidator(Validator validator) {
        this.validator = validator;
    }
    protected boolean predicate();
    protected boolean isInvalid();

    public final boolean isValid() {
        if (!this.validator.isValid() && predicate() && isInvalid())
            return false;
        return true;
    }
}

public class CheckInventory extends AbstractValidator {
    public CheckInventory(Validator validator) {
        super(validator);
    }
    @Override
    public boolean predicate() {
        return true;
    }
    @Override
    public boolean isInvalid() {
        // same code as your CheckInventory method
    }
}

public class PreOrder extends AbstractValidator {
    public CheckInventory(Validator validator) {
        super(validator);
    }
    @Override
    public boolean predicate() {
        return true;
    }
    @Override
    public boolean isInvalid() {
        // same code as your PreOrder method
    }
}
现在,您的方法看起来更加优雅:

public void MyMethod() {
    bool success = false;
    try {
        Validator validator = new GetNewOrders();
        validator = new CheckInventory(validator);
        validator = new PreOrder(validator);
        success = validator.isValid();
    } finally {
        if (!success) {
            // do something
        }
    }
} 

可以在一行中创建Validator对象,但我更喜欢这种样式,因为它可以明确验证的顺序。在链中创建新的验证链接是对AbstractValidator类进行子类化以及谓词和isInvalid方法的实现。

好吧,我不喜欢这样的代码:获取订单列表,然后处理它们,然后在出现错误时停止处理它们,当然它应该跳过该顺序并移动到下一个?唯一完全失败的是数据库(订单源、预订单目的地)死机时。我认为整个逻辑确实有点古怪,但可能是因为我没有你所用语言的经验

try {
  // Get all of the orders here
  // Either in bulk, or just a list of the new order ids that you'll call the DB
  // each time for, i'll use the former for clarity.
  List<Order> orders = getNewOrders();

  // If no new orders, we will cry a little and look for a new job
  if (orders != null && orders.size() > 0) {
    for (Order o : orders) {
      try {
        for (OrderItem i : o.getOrderItems()) {
          if (checkInventory(i)) {
            // Reserve that item for this order
            preOrder(o, i);
          } else {
            // Out of stock, call the magic out of stock function
            failOrderItem(o, i);
          }
        }
      } catch (OrderProcessingException ope) {
        // log error and flag this order as requiring attention and
        // other things relating to order processing errors that aren't database related
      }
    }
  } else {
    shedTears();
  }
} catch (SQLException e) {
  // Database Error, log and flag to developers for investigation
}
试试看{
//把所有的订单都拿到这里
//可以是批量的,也可以只是一个新订单ID列表,您将调用DB
//为了清晰起见,每次我都会使用前者。
List orders=getNewOrders();
//如果没有新订单,我们会哭一哭,寻找新的工作
if(orders!=null&&orders.size()>0){
对于(订单o:订单){
试一试{
对于(OrderItem i:o.getOrderItems()){
如果(检查库存(i)){
//为这次订购保留那个项目
前序(o,i);
}否则{
//缺货,调用magic缺货函数
失效顺序项(o,i);
}
}
}捕获(OrderProcessingException操作){
//记录错误并将此订单标记为需要注意和
//与订单处理错误相关的其他事项与数据库无关
}
}
}否则{
shedTears();
}
}捕获(SQLE异常){
//数据库错误、日志和标志发送给开发人员进行调查
}

对于一组简单的指令来说,您的新方法并没有那么糟糕,但是当添加额外的步骤时会发生什么呢?您/您是否曾经要求过交易行为?(如果预订单失败怎么办?或者如果预订单失败后的下一步怎么办?)

展望未来,我将使用命令模式:

…并将每个操作封装为实现Execute()和Undo()的具体命令


然后,只需创建一个命令队列并循环,直到失败或出现一个空队列。如果任何步骤失败,只需停止并按照前面命令的顺序执行Undo()。简单。

克里斯解决方案是最正确的。但我认为你不应该做超出你需要的事情。解决方案应该是可扩展的,这就足够了

  • 更改参数值是一种不好的做法
  • 永远不要使用空的泛型catch语句,至少要添加注释说明为什么要这样做
  • 使这些方法抛出异常,并在适当的地方处理它们
  • 所以现在它更优雅了:)


    我也这么认为。这也缩短了你的代码,因为你不再需要if语句了。而且FWIW,catch块应该对它捕获的异常做一些事情——而不是默默地忽略它们,这有点挫败了异常的意义…@ocdecio——我不同意。异常行为和方法失败之间存在(或可能存在)差异。如果没有订单,GetOrders可能会失败,但如果连接字符串无效,则会导致异常,例如@tvanfosson:“如果没有订单,GetOrders可能会失败”-想想看,没有订单是错误吗???@ocdecio-不,我不这么认为。如果没有参考当前的代码,我想说,如果还没有输入订单,则没有订单是正常情况。如果我正在搜索一个特定的顺序,但没有找到它,这可能是一个例外。在方法的末尾,如果hasfiled=true,我必须执行一些特殊的操作。(bu)
    public void MyMethod()
    {
       try
       {
          GetNewOrders();
          CheckInventory();
          PreOrder();
          // etc
       }
       finally
       {
          // do something
       }
    }