在面向对象编程 (OOP) 领域,用户经常发现自己在复杂的业务逻辑流中导航。然而,这个过程并不总是一帆风顺的,因为意外的情况可能会扰乱预定的路线。想象一下,一个用户使用不正确的输入调用一个函数——这是需要我们作为开发人员注意的常见情况。为了解决这种情况,我们有两种不同的方法:抛出异常和返回结果。在本文中,我们将深入探讨这些方法的复杂性,探索它们如何有效地引导用户处理错误消息,确保无缝和用户友好的体验。
异常是表示程序执行期间发生的异常事件或错误的对象。当出现异常情况时,例如无效操作或意外情况,将抛出异常,中断程序的正常流程。
异常提供了一种结构化的方式来处理和管理错误。它们将错误信息从发生错误的位置传播到可以处理错误的位置。例外的一个优点是它们能够被抛出而不必担心呼叫者或被呼叫者。让我们考虑一个例子来说明这一点:
public class Repository {
public Customer getByID(int id) {
var customer = context.customers.where(e => e.id == id).FirstOrDefault();
if (customer == null)
throw new NotFoundException($"customer with id {id} not found");
}
}
public class Service {
public Customer getCustomerDetails(int id) {
var customer = repository.getByID(id);
if (customer.isActive == false)
throw new CustomerIsDeActivatedException(id);
// or throw new MyBusinessLogicException(code, message)
string customerType = "all";
if (customer.age > 18 25 && customer.age < 25)
customerType = "young"
if (customer.age > 25 &&customer.age < 45)
customerType = "adult"
if (customer.age < 18)
throw new MyBusinessLogicException("4403", "customer is not allowed")
return new CustomerDto {
id = customer.id,
fullName = customer.firstName + " " + customer.lastName
}
}
}
public class Controller {
[HttpGet]
public IActionResult getByID(int id) {
try {
var customer = service.getByID(id);
return Ok(new Result {
status = 200,
message = "everything is ok"
data = customer
})
} catch(Exception e) {
return Ok(new Result {
status = 400,
message = e.message
})
}
}
}
如示例中所示,异常允许编译器忽略后续代码并搜索适当的处理程序。它们可以遍历层,而无需了解每一层,从而使代码干净,并减少检查正确结果的人为错误。但是,请务必注意,在性能至关重要的情况下,应避免过度使用异常。
另一种方法是返回结果,其中结果是用作函数返回类型的抽象。它使我们能够保持跨职能的标准化。结果类型的常见示例如下:
public class Result
{
string statusCode;
string message;
object data;
}
使用外部服务时,开发人员通常会通过检查状态代码来验证结果。这种方法提供了对软件的完全控制,使我们能够在结果不符合预期时生成更有意义的消息。可以通过以下代码描述基于结果的控制流的另一个版本:
public class Repository {
public Result getByID(int id) {
var customer = context.customers.where(e => e.id == id).FirstOrDefault();
if (customer == null) {
return new Result {
statusCode = 404,
message = "data not found"
data = null
}
} else {
return new Result {
statusCode = 200,
message = null
data = customer
}
}
}
}
public class Service {
public Customer getCustomerDetails(int id) {
var customerResult = repository.getByID(id);
if (customerResult.statusCode != 200)
return customerResult;
var customer = customerResult.data as Customer;
if (customer.isActive == false) {
new Result {
statusCode = 4001,
message = "customer is not active"
data = null
}
}
string customerType = "all";
if (customer.age > 18 25 && customer.age < 25)
customerType = "young"
if (customer.age > 25 &&customer.age < 45)
customerType = "adult"
if (customer.age < 18)
{
new Result {
statusCode = 4403,
message = "customer is not allowed"
data = null
}
}
var finalData = new CustomerDto {
id = customer.id,
fullName = customer.firstName + " " + customer.lastName
}
return new Result {
statusCode = 200,
message = null
data = finalResult
}
}
}
public class Controller {
[HttpGet]
public IActionResult getByID(int id) {
var customerResult = service.getByID(id);
if (customerResult.statusCode != 200)
return BadRequest(customerResult);
return ok (customerResult);
}
}
在决定引发异常和返回结果时,请务必考虑对整体代码结构的影响以及团队的特定需求。在引发异常的情况下,域驱动设计 (DDD) 中的业务规则冲突和不变量是基于异常的方法的良好候选者。这种方法可确保代码的一致性和清晰度,因为异常用于传达特殊情况。
但是,如果您主要关心的是验证请求数据,则返回结果可能是一个专业的选择。这种方法允许更明确和可控的系统流,为用户提供有意义的反馈。它使您能够处理不同的方案并返回有关验证过程的详细信息。
值得注意的是,一些开发人员更喜欢为所有验证(包括输入和业务验证)抛出异常。这种方法也是有效的,因为它在整个应用程序中促进了一致的代码样式。通过一致地使用异常,开发人员可以实现更高级别的代码一致性和可维护性。
虽然异常可能会在某些方案中影响性能,例如处理大型数据集并为数百万用户提供服务,但在较小规模的应用程序中,实际影响可能并不明显。评估特定用例的性能要求,并评估异常的潜在影响是否超过它们在代码结构和错误处理方面提供的好处,这一点很重要。
在处理面向对象编程中的错误时,开发人员有两种主要方法:抛出异常和返回结果。异常提供了一种结构化的方式来处理错误,允许更简洁的代码并减少手动结果检查的需要。另一方面,返回结果可以更好地控制系统流,从而更轻松地分离服务。这些方法之间的选择取决于性能要求和团队代码样式等因素。通过了解每种方法的复杂性,开发人员可以做出明智的决策,以确保在其应用程序中获得无缝且用户友好的体验。