考虑这个具有业务逻辑的类:
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
}
}
该类包含一些业务逻辑,并执行一些横切关注点。虽然毫无疑问此类违反了Open/Closed Principle,此类是否违反了Single Responsibility Principle?
我有疑问,因为类本身不负责授权用户,分析性能和处理事务。
毫无疑问,这是一个糟糕的设计,因为课程仍然(静态地)取决于那些横切关注点,但仍然是:它是否违反了SRP。如果是这样,为什么会这样?
答案 0 :(得分:2)
这是一个很好的问题,标题有点误导(你不可能在没有“调用其他代码”的情况下构建应用程序)。请记住,SOLID原则比必须遵循的绝对规则更为准则;如果你把SRP用于其逻辑结论,那么每个类最终会得到一个方法。最大限度地减少交叉问题影响的方法是创建一个尽可能容易使用的外观。在你的例子中,你做得很好 - 每个横切关注只使用一行。
实现此目标的另一种方法是AOP,可以使用PostSharp或IoC interception
在C#中实现答案 1 :(得分:1)
类方法协调其他类活动没有任何问题,这不会打破SRP。如果这些类的逻辑是OrderShipper
的一部分,你将打破它。
我不确定PerformanceProfiler
是做什么的,但它是唯一看起来很奇怪的组件。
答案 2 :(得分: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);
这非常可靠。
答案 3 :(得分:1)
是的,它确实打破了SRP,至少根据班级名称。
类本身不负责授权用户,分析性能和处理事务。
您正在回答自己,它应该只包含运输订单逻辑。它不应该是静态的(为什么它是静态的?!)。
@ jgauffin提供的解决方案是一种可行性,尽管我并不完全相信OrderShipper应该知道一个事务,或者它应该只是一个事务的一部分。此外,性能分析器IMO在这个类中没有位置。但只有这些信息我无法提出解决方案。然而,分析是一个交叉关注的问题,在这个类之外处理可能更好,可能有一个属性。
顺便说一下,使用消息驱动的方法(如jgauffin所建议的那样)它应该允许基础架构提供分析和可靠性(HandleWithRetries)支持