我目前正在重构一个使用逻辑流异常的应用程序。这段代码难以阅读和维护,并且让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;
}
}
}
}
答案 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风格的方法而不是程序方法。
这是一个高级别的答案,但我很累,并且没有精力自己重新编写代码:)