技術共有

デザインパターン 責任連鎖パターン

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Chain of Responsibility パターンは、複数のオブジェクトがリクエストを順番に処理できるようにする動作設計パターンであり、各オブジェクトはリクエストを処理するか次のオブジェクトに渡すかを選択できます。このパターンでは、リクエストの送信者と受信者を分離することで、柔軟性とスケーラビリティが向上します。以下は、責任連鎖モデルの詳細な紹介です。

1. 定義と核となる考え方

責任連鎖モデルの中核は、リクエスト チェーンとチェーンの終端の識別を設計することです。複数のリクエスト処理オブジェクトをチェーンに接続し、チェーン内のオブジェクトがリクエストの処理を決定するまで、リクエストがチェーン上を通過できるようにします。リクエストを行うクライアントは、チェーン内のどのオブジェクトが最終的にリクエストを処理するのかを知りません。そのため、システムはクライアントに影響を与えることなく動的に再編成し、責任を割り当てることができます。

2. クラス図と主な役割

クラス図:

責任連鎖モデルには主に次の役割が含まれます。

  1. 抽象ハンドラ (ハンドラ) : リクエストを処理するためのインターフェースを定義します。必要に応じて、インターフェイスは次のインターフェイスへの参照を設定して返すメソッドを定義できます。この役割は通常、抽象クラスまたはインターフェイスによって実装されます。

  2. コンクリートハンドラー : リクエストを受信した後、特定のプロセッサはリクエストを処理するか、リクエストを次の当事者に渡すかを選択できます。具象プロセッサは次のホームへの参照を保持しているため、必要に応じて次のホームにアクセスできます。

  3. クライアントクラス(クライアント): 処理チェーンを作成し、チェーン ヘッドの特定のプロセッサ オブジェクトにリクエストを送信します。

3. 適用可能なシナリオ

責任連鎖モデルは、次のシナリオに適しています。

  1. 複数のオブジェクトが共同してタスクを処理する: たとえば、複数レベルの承認システムでは、最終的な承認結果が得られるまで、承認者の権限とレベルに基づいて承認リクエストが次のレベルの承認者に渡されます。

  2. 動的結合処理の流れ: 責任チェーンを柔軟に構成することで、処理オブジェクトを動的に組み合わせてさまざまな処理プロセスを実装できます。

  3. リクエストの送信者と受信者の直接結合を避ける: リクエストを責任チェーンに渡すことにより、リクエストの送信者は特定の処理オブジェクトを知る必要がなくなり、オブジェクト間の依存関係が軽減されます。

4. メリットとデメリット

アドバンテージ
  1. カップリングを減らす: リクエストの送信者と受信者を分離します。誰が処理するかに関係なく、リクエストは送信されるだけです。
  2. オブジェクト割り当ての柔軟性の向上: チェーン内のメンバーを変更したり、順序を移動したりすることで、責任を動的に追加または削除できます。
  3. オブジェクトを単純化する: オブジェクトはチェーンの構造を知る必要はありません。
  4. 新しいリクエスト処理クラスを追加すると便利です: オープニングとクロージングの原則に従って、既存のコードを変更することなく、いつでも新しいプロセッサを責任チェーンに追加できるため、優れたスケーラビリティが実現します。
欠点がある
  1. リクエストが受け入れられるという保証はありません: 責任チェーンが正しく構成されていない場合、またはプロセッサがリクエストを正しく処理しない場合、リクエストは処理されない可能性があります。
  2. パフォーマンスの問題: 責任の連鎖が長すぎる場合、または責任の連鎖内でリクエストが頻繁に受け渡される場合、パフォーマンスに影響が出る可能性があります。
  3. デバッグが不便: 責任の連鎖が特に長く、多くのリンクがある場合、再帰的アプローチによりデバッグ中にロジックがより複雑になる可能性があります。

5. 応用シナリオ

責任連鎖モデルは、以下を含むがこれらに限定されない多くの分野で広く使用されています。

  1. ロギングシステム: コンソール ロガー、ファイル ロガー、データベース ロガーなどのログ レベルに応じて、ログ メッセージをさまざまなロガーに渡します。
  2. 例外処理システム: 例外をログ、電子メール通知、例外表示などの種類に応じて分類します。
  3. 多段階の承認システム: たとえば、休暇承認、購入承認など、承認リクエストは承認者の権限とレベルに応じて次のレベルの承認者に渡されます。

6. 実装例

以下は、責任連鎖パターンの簡単な実装例です。これは、ログ メッセージを処理し、ログ レベル (DEBUG、INFO、WARN、ERROR など) に応じてメッセージをさまざまなプロセッサに渡すために使用されます。

  1. // 抽象处理者
  2. abstract class LogHandler {
  3. protected int level;
  4. protected LogHandler nextHandler;
  5. public void setNextHandler(LogHandler nextHandler) {
  6. this.nextHandler = nextHandler;
  7. }
  8. //这个是精髓:他除了处理自己的逻辑,还会调用nextHandler进行处理
  9. public void logMessage(int level, String message) {
  10. if (this.level <= level) {
  11. write(message);
  12. }
  13. if (nextHandler != null) {
  14. nextHandler.logMessage(level, message);
  15. }
  16. }
  17. abstract protected void write(String message);
  18. }
  19. // 具体处理者:ErrorLogHandler
  20. class ErrorLogHandler extends LogHandler {
  21. public ErrorLogHandler(int level) {
  22. this.level = level;
  23. }
  24. @Override
  25. protected void write(String message) {
  26. System.out.println("ErrorLogHandler: " + message);
  27. }
  28. }
  29. // 具体处理者:WarnLogHandler
  30. class WarnLogHandler extends LogHandler {
  31. public WarnLogHandler(int level) {
  32. this.level = level;
  33. }
  34. @Override
  35. protected void write(String message) {
  36. System.out.println("WarnLogHandler: " + message);
  37. }
  38. }
  39. // 具体处理者:InfoLogHandler
  40. class InfoLogHandler extends LogHandler {
  41. public InfoLogHandler(int level) {
  42. this.level = level;
  43. }
  44. @Override
  45. protected void write(String message) {
  46. System.out.println("InfoLogHandler: " + message);
  47. }
  48. }
  49. // 客户端代码
  50. public class ChainPatternDemo {
  51. private static LogHandler getChainOfLoggers() {
  52. // 创建链中的处理者
  53. LogHandler errorLogHandler = new ErrorLogHandler(3);
  54. LogHandler warnLogHandler = new WarnLogHandler(2);
  55. warnLogHandler.setNextHandler(errorLogHandler);
  56. LogHandler infoLogHandler = new InfoLogHandler(1);
  57. infoLogHandler.setNextHandler(warnLogHandler);
  58. return infoLogHandler;
  59. }
  60. public static void main(String[] args) {
  61. LogHandler loggerChain = getChainOfLoggers();
  62. loggerChain.logMessage(1, "This is an informational message.");
  63. loggerChain.logMessage(2, "This is a warning message.");
  64. loggerChain.logMessage(3, "This is an error message.");
  65. }
  66. }

この例では、3 つの具体的なログ ハンドラー クラスを定義します (ErrorLogHandlerWarnLogHandlerInfoLogHandler )、それぞれ異なるレベルのログ メッセージを処理します。各ハンドラーにはレベル (level )、このレベルのメッセージを処理する必要があるかどうかを決定するために使用されます。電話することでlogMessageメソッドでは、リクエストはチェーン内の最初のハンドラーに渡されます (infoLogHandler )、独自のレベルと処理ロジックに基づいてメッセージを処理するかどうかを決定し、(処理されない場合は) チェーン内の次のプロセッサにリクエストを渡します。このプロセスは、チェーンの終わりまで、またはリクエストが処理されるまで継続します。

実際のアプリケーションでは、次のことが必要になる場合があることに注意してください。LogHandlerこのクラスには、より複雑なログ処理ロジックと構成をサポートするためのメソッドとプロパティが追加されています。さらに、ログ レベルでは通常、列挙型が使用されます (enum) を整数の代わりに使用して、コードの可読性と保守性を向上させます。

7. 結論

責任連鎖パターンは、リクエストを処理する複数のオブジェクトをチェーンに接続し、チェーン上のオブジェクトがリクエストの処理を決定するまでリクエストがチェーン上を通過できるようにすることで、リクエストの柔軟な処理とシステムのスケーラビリティを実現します。

責任連鎖モデルが役立つ場合は、忘れずに「いいね」を押して保存してください。