我会对你的第一种方法提出异议。我不确定所有单独的业务类是否会以某种方式共享一个Delete
方法的相同接口。删除客户所需的参数可能与删除订单所需的参数不同。强迫他们共享相同的界面似乎很奇怪。这样做可能会不必要地限制将来代码的灵活性。此外,删除客户的业务逻辑会涉及盲目循环其他对象,没有特定顺序,并在所有对象上调用方法,这似乎很奇怪Delete
。我认为您希望更好地控制它们被删除的顺序以及当其中一种删除方法失败时如何处理它。
我建议首先在更高的层次上考虑它。您实际需要哪些业务方法?根据您描述的场景,我可以看到两种业务方法:
- 获取过去 6 年没有订单的所有客户的列表
- 删除客户(连同其所有订单)
由于这两种方法都与客户相关,因此将它们组合成一个单一的客户业务类是有意义的。例如:
Public Interface ICustomerBusiness
Function GetStaleCustomers(timeSinceLastOrder As TimeSpan) As IList(Of CustomerDto)
Sub DeleteCustomer(customerId As Integer)
End Interface
一旦你像这样封装了业务逻辑,现在数据访问层如何实现就无关紧要了。客户端调用那些简单的业务层方法,不必关心幕后的逻辑是如何工作的。将业务逻辑封装在其自己的层中,您可以自由地以不同的方式重写它,而无需重写任何客户端代码。
那么该业务类内部的逻辑是什么样的呢?它可以是对数据访问方法的一次调用,该方法通过一个庞大的 SQL 命令完成所有工作,也可以进行多次调用以分别执行每个步骤。这真的取决于你。显然前者效率更高,但后者更灵活。这一切都取决于您的需求。下面是一个简单的示例,说明每个可能的样子:
Public Sub DeleteCustomer(id As Integer)
_customerDataAccess.DeleteCustomerAndOrders(id)
End Sub
' or...
Public Sub DeleteCustomer(id As Integer)
For Each i As OrderDto In _orderBusiness.GetOrdersByCustomer(id)
_orderBusiness.DeleteOrder(i.Id)
Next
_customerDataAccess.DeleteCustomer(id)
End Sub
出于多种原因,第二种选择会更加灵活。例如:
- 您可以更好地控制正在发生的事情和时间。如有必要,您可以在此过程中提供详细的状态更新。它还允许您在出现故障时提供详细的跟踪记录和更精确的错误消息。
- 删除订单的业务逻辑将分解为一个单独的可重用业务类。如果您只需要从代码中的其他位置删除一个订单,您可以通过通用代码执行此操作。