调用其他代码是否违反了(SOLID)单一责任原则(SRP)
本文关键字:SOLID 单一 责任 SRP 原则 代码 其他 是否 调用 | 更新日期: 2023-09-27 18:08:21
用业务逻辑考虑这个类:
public static class OrderShipper
{
public static void ShipOrder(Order order) {
AuthorizationHelper.AuthorizedUser();
using (new PerformanceProfiler()) {
OperationRetryHelper.HandleWithRetries(() => ShipOrderInTransaction(order));
}
}
private static void ShipOrderInTransaction(Order order) {
using (var transaction = new TransactionHelper()) {
ShipOrderInternal(order);
transaction.Commit();
}
}
private static void ShipOrderInternal(order) {
// lots of business logic
}
}
类包含一些业务逻辑,并执行一些横切关注点。虽然毫无疑问这个类违反了开/闭原则,但是这个类是否违反了单一职责原则?
我对此表示怀疑,因为类本身并不负责授权用户、分析性能和处理事务。
毫无疑问,这是一个糟糕的设计,因为类仍然(静态地)依赖于那些横切关注点,但是仍然:它是否违反了SRP ?如果是这样,为什么会这样?这是一个好问题,标题有点误导人(不可能不"调用其他代码"就构建一个应用程序)。记住,SOLID原则更多的是指导方针,而不是必须遵循的绝对规则;如果按照SRP的逻辑得出结论,那么最终每个类只有一个方法。将横切关注点的影响最小化的方法是创建一个尽可能容易使用的立面。在您的示例中,您做得很好——每个横切关注点只使用一行。
实现这一点的另一种方法是通过AOP,这在c#中可以通过使用PostSharp或通过IoC拦截一个类方法协调一些其他类的活动并没有错,这并没有破坏SRP。如果这些类的逻辑是OrderShipper
的一部分,您将破坏它。
我不确定PerformanceProfiler
做什么,但是唯一的组件,看起来很奇怪在那里。
让我们通过将类转换为命令来使它更明显:
// Command pattern
public class ShipOrder
{
ITransactionFactory _transactionFactory;
public OrderShipper(ITransactionFactory factory)
{
if (factory == null) throw new ArgumentNullException("factory");
_transactionFactory = factory;
}
[PrincipalPermission(Roles = "User")]
public void Execute(Order order)
{
if (order == null) throw new ArgumentNullException("order");
using (new PerformanceProfiler())
{
HandleWithRetries(() => ShipOrderInTransaction(order));
}
}
private void ShipOrderInTransaction(Order order)
{
using (var transaction = _transactionFactory.Create())
{
ShipOrderInternal(order);
transaction.Commit();
}
}
protected void ShipOrderInternal(order)
{
// bussiness logic which is divided into different protected methods.
}
}
因此你可以这样调用它:
var cmd = new ShipOrder(transactionFactory);
cmd.Execute(order);
是的,它确实违反了SRP,至少根据类名。
类本身不负责授权用户、分析性能和处理事务。
您正在回答自己,它应该只包含发货订单逻辑。它不应该是静态的(为什么是静态的?!)
@jgauffin提供的解决方案是一种可能性,尽管我不完全相信OrderShipper应该知道事务,或者它应该只是事务的一部分。此外,在我看来,性能分析器在这个类中没有位置。但只有这些信息,我无法提出解决方案。然而,分析是一个横切问题,最好在这个类之外处理,也许可以使用一个属性。
顺便说一句,使用消息驱动的方法(如jgauffin所建议的),它应该允许基础设施提供分析和可靠性(HandleWithRetries)支持