11

こんにちは、Simple Injector DI ライブラリを使用しており、コマンド パターンを中心に設計されたアーキテクチャ モデルに関する非常に興味深い資料をフォローしています。

コンテナーは の有効期間を管理しUnitOfWorkます。コマンドを使用して、データベースに対して特定の機能を実行しています。

私の質問は、たとえば、AddNewCustomerCommand別のサービスへの別の呼び出しを実行する (つまり、テキスト メッセージを送信する) などのコマンドがある場合、設計の観点から、これは受け入れられるか、またはこれをより高いレベルで行う必要があるかどうかです。これを行うのが最善ですか?

コード例は次のとおりです。

public class AddNewBusinessUnitHandler
    : ICommandHandler<AddBusinessUnitCommand>
{
    private IUnitOfWork uow;
    private ICommandHandler<OtherServiceCommand> otherHandler;

    AddNewBusinessUnitHandler(IUnitOfWork uow, 
        ICommandHandler<OtherServiceCommand> otherHandler)
    {
        this.uow = uow;
        this.otherHandler = otherHandler;
    }

     public void Handle(AddBusinessUnitCommand command)
     {
        var businessUnit = new BusinessUnit()
        {
            Name = command.BusinessUnitName,
            Address = command.BusinessUnitAddress
        };

        var otherCommand = new OtherServiceCommand()
        {
            welcomePostTo = command.BusinessUnitName
        };

        uow.BusinessUnitRepository.Add(businessUnit);

        this.otherHandler.Handle(otherCommand);
     }
}
4

1 に答える 1

21

(ビジネス)コマンドのアーキテクチャビューによって異なりますが、ユースケースとコマンドの間に1対1のマッピングを作成するのは非常に自然なことです。その場合、プレゼンテーション層は(ボタンのクリックなどのシングルユーザーアクション中に)コマンドを作成して実行するだけです。さらに、それはその単一のコマンドを実行するだけで、それ以上のことはしません。そのユースケースを実行するために必要なすべては、そのコマンドによって実行される必要があります。

とはいえ、テキストメッセージの送信、データベースへの書き込み、複雑な計算の実行、Webサービスとの通信、およびビジネスのニーズを操作するために必要なその他すべては、そのコマンドのコンテキスト中に実行する必要があります(または後で発生するようにキューに入れられます)。プレゼンテーションにとらわれない方法で要件を表すのはそのコマンドであるため、前ではなく、後ではありません。

これは、コマンドハンドラー自体がこれらすべてを実行する必要があるという意味ではありません。ハンドラーが依存する他のサービスに多くのロジックを移動するのは非常に自然なことです。ITextMessageSenderたとえば、インターフェイスに応じてハンドラーを想像できます。

別の議論は、コマンドハンドラーが他の依存コマンドハンドラーに依存する必要があるかどうかです。ユースケースを見ると、大きなユースケースが複数の小さなサブユースケースで構成されている可能性は低いので、その意味では不思議ではありません。ここでも、コマンドとユースケースの間に1対1のマッピングがあります。

ただし、ネストされたコマンドハンドラーの相互依存関係の深い依存関係グラフがあると、コード内の移動が複雑になる可能性があるため、これをよく見てください。ITextSessageSenderたとえば、を使用する代わりに注入する方がよいICommandHandler<SendTextMessageCommand>場合があります。

ハンドラーをネストできるようにすることのもう1つの欠点は、インフラストラクチャの処理が少し複雑になることです。たとえば、トランザクション動作を追加するデコレータでコマンドハンドラをラップする場合、ネストされたハンドラが最も外側のハンドラと同じトランザクションで実行されることを確認する必要があります。私は今日これで私のクライアントをたまたま助けました。信じられないほど難しいことではありませんが、理解するのに少し時間がかかります。これはトランザクションの境界でも実行されるため、デッドロック検出などにも同じことが当てはまります。

さらに、デッドロック検出は、このコマンド/ハンドラーパターンの威力を示す良い例です。他のほとんどすべてのアーキテクチャスタイルでは、この動作をプラグインすることが不可能になるためです。例を見るには、この記事DeadlockRetryCommandHandlerDecoratorクラスを見てください)。

于 2012-06-08T14:58:50.623 に答える