重构工作流的异常

时间:2009-12-03 05:13:19

标签: c# exception refactoring

我目前正在重构一个使用逻辑流异常的应用程序。这段代码难以阅读和维护,并且让S.O.L.I.D的粉丝在阅读时会像我一样哭泣(更不用说我职业生涯中见过的最长的抓手)。

我的问题是您可以使用哪种模式来使维护更容易,或者您将如何进行重构?

public void CallExternalServices(ICriteria criteria)
{
    try
    {
        someResult = ExternalService1.SomeMethod(criteria);
    }
    catch (Service1Exception service1Exception)
    {
        if (criteria.SomeValue == "1")
        {
            if (service1Exception.InnerException != null 
                && service1Exception.InnerException.InnerException != null
                && service1Exception.InnerException.InnerException is TargetSystemException)
            {
                TargetSystemException targetSystemException = (TargetSystemException)service1Exception.InnerException.InnerException;
                if (targetSystemException.ErrorStatus.IsServiceDownForMaintenance())
                {
                    // Call internal method to perform some action
                    SendNotification("Service down for maintenance.")
                }
            }
        }
        else if (criteria.SomeValue == "2")
        {
            if (service1Exception.InnerException != null 
                && service1Exception.InnerException.InnerException != null
                && service1Exception.InnerException.InnerException is TargetSystemException)
            {
                TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
                if (targetSystemException.ErrorStatus.IsBusy())
                {
                    // Call to some internal method to perform an action
                    SendDifferentNotification()

                    criteria.SetSomeFlagToBe = true;

                    try
                    {
                        someResult = ExternalService2.SomeOtherMethod(criteria);
                    }
                    catch (Service2Exception service2Exception)
                    {
                        if (service2Exception.InnerException != null 
                            && service2Exception.InnerException.InnerException != null
                            && service2Exception.InnerException.InnerException is TargetSystemException)
                        {
                            TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
                            if (targetSystemException.ErrorStatus.HasNumberOfDailyTransactionsBeenExceeded())
                            {
                                // Call internal method to perform some action
                                SendNotification("Number of daily transactions exceeded.")
                            }
                        }
                        else if (service2Exception.InnerException != null
                            && service2Exception.InnerException.InnerException != null
                            && service2Exception.InnerException.InnerException is FaultException)
                        {
                            FaultException faultException = service2Exception.InnerException.InnerException as FaultException;

                            if (faultException.Detail != null
                                && faultException.Detail.FaultMessage.Equals("SomeValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
                            {
                                return someResult;
                            }
                            else
                            {
                                throw service2Exception;
                            }
                        }
                        else
                        {
                            throw service2Exception;
                        }
                    }

                    if (someResult != null)
                    {
                        // perform another action
                        SomeActionInvoker.ExecuteAcitonAgainst(someResult);
                    }
                }
            }
            else if (service1Exception.InnerException != null
                     && service1Exception.InnerException.InnerException != null
                     && service1Exception.InnerException.InnerException is FaultException)
            {
                FaultException faultException = service1Exception.InnerException.InnerException as FaultException;

                if (faultException.Detail != null
                    && faultException.Detail.FaultMessage.Equals("SomeOtherValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
                {
                    return someResult;
                }
                else
                {
                    throw service1Exception;
                }
            }
            else
            {
                throw service1Exception;
            }
        }
    }
}

3 个答案:

答案 0 :(得分:1)

总而言之,我认为通过将一些东西分解为一些辅助方法可以帮到你。例如,您可以提取看起来像这样的支票

if (<exception-instance>.InnerException != null && 
    <exception-instance>.InnerException.InnerException != null && 
    <exception-instance>.InnerException.InnerException is <exception-type>)

进入布尔方法;我粗略地瞥了一眼这样的代码至少3次。

另外,我建议将第二个顶级案例提取为错误处理方法;也许是嵌套的if语句。

答案 1 :(得分:1)

查看Michael Feathers的有效使用遗留代码,特别是第22章(我需要更改怪物方法,我无法为其编写测试)。对于像你这样的情况,有很多很棒的技巧。就个人而言,在这种情况下,我通常最终会从较长方法的各个部分中提取方法,并摆脱整个方法中使用的局部变量;这几乎总是麻烦。

答案 2 :(得分:0)

首先将方法重构为多个方法。你已经有太多的缩进程度了。

之后,考虑是否可以将一些新方法提取到其他对象中,并使用IoC风格的方法而不是程序方法。

这是一个高级别的答案,但我很累,并且没有精力自己重新编写代码:)