4

このクラスをビジネス ロジックで考えると、次のようになります。

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に違反していますか?もしそうなら、これはなぜですか?

4

4 に答える 4

2

良い質問です。タイトルは少し誤解を招きます (「他のコードを呼び出す」ことなくアプリケーションを構築できる可能性は低いです)。SOLID の原則は、従わなければならない絶対的なルールというよりも、ガイドラインにすぎないことを忘れないでください。SRP を論理的な結論に導くと、クラスごとに 1 つのメソッドが作成されます。分野横断的な懸念の影響を最小限に抑える方法は、できるだけ使いやすいファサードを作成することです。あなたの例では、これをうまく行っています-各横断的関心事は1行しか使用していません。

これを実現するもう 1 つの方法はAOPを使用することです。これは C# でPostSharpを使用するか、IoC インターセプトを使用して可能です。

于 2013-04-10T12:56:38.917 に答える
1

はい、少なくともクラス名によると、SRPを壊します。

クラス自体は、ユーザーの承認、パフォーマンスのプロファイリング、およびトランザクションの処理について責任を負いません。

あなたは自分自身に答えています。それには出荷注文ロジックのみが含まれている必要があります。また、静的であってはなりません (なぜ静的なのですか?!)。

@jgauffin が提供する解決策は可能性ですが、OrderShipper がトランザクションについて知っているべきか、トランザクションの一部であるべきかについては完全には確信が持てません。また、パフォーマンス プロファイラーである IMO は、このクラスにはありません。しかし、この情報だけでは解決策を提案できません。ただし、プロファイリングは分野横断的な問題であり、おそらく属性を使用して、このクラスの外で処理する方がよい場合があります。

ところで、(jgauffin で提案されているように) メッセージ駆動型のアプローチを使用すると、インフラストラクチャがプロファイリングと信頼性 (HandleWithRetries) のサポートを提供できるようになります。

于 2013-04-10T12:56:12.247 に答える
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 に答える