外部リソース (DB、Web サービス呼び出しなど) を使用する私のプロジェクトのすべてのメソッドは、ログを記録する必要があります。
信じられません。ログが多すぎる可能性があります。
文は同じように見えますが、パラメーターが異なります (つまり、メソッド名)。
その場合、コードに一般的な抽象化が欠けている可能性があります。私の経験では、次のことを行う必要があります。
アーキテクチャに強く関連するコードの一般的な抽象化を持っています。
たとえば、コマンド ハンドラーに関するこの記事と、リポジトリとカスタム クエリに関するこの記事をご覧ください。どちらの記事も、アーキテクチャの概念に関する単一の汎用インターフェイスを定義しています。(私の回答の残りの部分を理解するには、少なくとも最初の記事を読む必要があります)。
汎用インターフェイスを使用すると、関連する一連の操作全体をデコレータで簡単にラップできます。たとえば、ユース ケースを実行するすべての操作をラップできる次のデコレータを考えてみましょう。
public class LoggingCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> decoratee;
private readonly ILogger logger;
public LoggingCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee,
ILogger logger)
{
this.decoratee = decoratee;
this.logger = logger;
}
void ICommandHandler<TCommand>.Handle(TCommand command)
{
using (new AutoLog())
{
this.decoratee.Handle(command);
}
}
}
AutoLog クラスをできるだけ速く動作させるには、どのように実装すればよいですか?
ご存知のように、デコレータは単なる薄いラッパーであり、オーバーヘッドはほとんどありません。このアプローチにより、通常はすべてのメソッド引数が 1 つのオブジェクトにパックされます。TCommand全体を XML、JSON、またはより読みやすい形式に単純にシリアル化でき、このコードを 1 回記述するだけで済むため、これはロギングに非常に便利です。
これはジェネリック型であるため、パフォーマンスが心配なので、LoggingCommandHandlerDecorator<TCommand>その型に静的コンストラクターを追加し (静的コンストラクターは、そのインターフェイスのクローズされたジェネリック バージョンごとに 1 回実行されます)、コードをプリコンパイルして、効率的にそのコマンド メッセージをシリアル化します。それに匹敵するものは絶対にありません。AOP フレームワークでさえ、リフレクションを使用し、メソッドのパラメーターにアクセスするときにボックス化を使用して動的配列を構築します。
このようなデコレータを適用することについて、「貧弱な」ことは何もないことに注意してください。ただし、アーキテクチャがSOLIDの原則に従っていない場合にこれを試すと、すぐに問題が発生します。これらの原則は、柔軟で保守可能なソフトウェアを入手するための鍵です。