4

Considering this class with business logic:

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
    }
}

The class contains some business logic, and executes some crosscutting concerns as well. Although there is no doubt about that this class violates the Open/Closed Principle, does this class violate the Single Responsibility Principle?

I'm in doubt, since the class itself is not responsible for authorizing the user, for profiling the performance and for handling the transaction.

There is no question about this that this is poor design, since the class is still (statically) depending on those crosscutting concerns, but still: Is it violating the SRP. If so, why is this?

4

4 回答 4

2

这是一个很好的问题,标题有点误导(你不可能在不“调用其他代码”的情况下构建应用程序)。请记住,SOLID 原则更多的是指导而不是必须遵守的绝对规则;如果您将 SRP 得出其合乎逻辑的结论,那么您最终将得到每个类一个方法。最小化横切关注点影响的方法是创建一个尽可能易于使用的外观。在您的示例中,您做得很好-每个横切关注点仅使用一行。

另一种实现这一点的方法是通过AOP,这可以在 C# 中使用PostSharp或通过IoC 拦截

于 2013-04-10T12:56:38.917 回答
1

让我们通过将类转换为命令来使其更加可见:

// 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);

这很扎实。

于 2013-04-10T12:37:53.707 回答
1

是的,它确实破坏了 SRP,至少根据类名。

类本身不负责授权用户、分析性能和处理事务。

您正在回答自己,它应该只包含运输订单逻辑。而且它不应该是静态的(为什么它是静态的?!)。

@jgauffin 提供的解决方案是一种可能性,尽管我不完全相信 OrderShipper 应该知道交易或者它应该只是交易的一部分。此外,性能分析器 IMO 在此类中也没有位置。但是只有这些信息我不能提出解决方案。虽然分析是一个横切的关注点,在这个类之外处理可能会更好,也许有一个属性。

顺便说一句,使用消息驱动的方法(如 jgauffin 所建议的)它应该允许基础设施提供分析和可靠性(HandleWithRetries)支持

于 2013-04-10T12:56:12.247 回答
1

协调一些其他类活动的类方法没有错,这并没有破坏 SRP。如果这些类的逻辑是OrderShipper.

我不确定是什么PerformanceProfiler,但它是唯一看起来很奇怪的组件。

于 2013-04-10T12:30:49.777 回答