Chain of responsibility

Behavioural Design Patterns (8 Part Series)

1 Observer
2 Strategy
4 more parts…
3 command
4 Chain of responsibility
5 Mediator
6 Memento
7 Template
8 State

As the name suggests, a chain of responsibility creates a chain of receiver objects to handle requests.
This pattern decouples the request’s sender and receiver based on the request type.
This pattern comes under the Behavioural pattern.

In this pattern each receiver object of the request has a reference to the next object if it can not handle the request, the request is passed down to the next receiver in the chain.

Let’s understand this by taking the example of a logging mechanism that logs messages based on the level of the message (request)

AbstractLogger

<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>
<span>public</span> <span>abstract</span> <span>class</span> <span>AbstractLogger</span><span>{</span>
<span>/** * TRACE < DEBUG < INFO < WARN < ERROR < FATAL * which means if the level is INFO, then INFO, WARN, ERROR and FATAL messages will be logged * but if the level is ERROR then only ERROR and FATAL messages will be logged */</span>
<span>//higher the number higher the priority</span>
<span>public</span> <span>static</span> <span>int</span> <span>DEBUG</span> <span>=</span> <span>1</span><span>;</span>
<span>public</span> <span>static</span> <span>int</span> <span>INFO</span> <span>=</span> <span>2</span><span>;</span>
<span>public</span> <span>static</span> <span>int</span> <span>ERROR</span> <span>=</span> <span>3</span><span>;</span>
<span>protected</span> <span>int</span> <span>LEVEL</span><span>;</span>
<span>//next Logger in the chain of responsibility</span>
<span>private</span> <span>AbstractLogger</span> <span>nextLogger</span><span>;</span>
<span>public</span> <span>void</span> <span>setNextLogger</span><span>(</span><span>AbstractLogger</span> <span>logger</span><span>){</span>
<span>this</span><span>.</span><span>nextLogger</span> <span>=</span> <span>logger</span><span>;</span>
<span>}</span>
<span>public</span> <span>void</span> <span>logMessage</span><span>(</span><span>int</span> <span>level</span><span>,</span> <span>String</span> <span>message</span><span>){</span>
<span>//If the logging level of the message is greater than the current Logger's LEVEL then it will be logged </span>
<span>//example if level = ERROR and this.LEVEL = INFO then the message will be logged as INFO has a lower priority than ERROR</span>
<span>if</span><span>(</span><span>this</span><span>.</span><span>LEVEL</span> <span><=</span><span>level</span><span>){</span>
<span>write</span><span>(</span><span>message</span><span>);</span>
<span>}</span>
<span>// else the message/request will be passed down to the next logger/object in the chain</span>
<span>else</span><span>{</span>
<span>if</span><span>(</span><span>nextLogger</span><span>!=</span><span>null</span><span>){</span>
<span>nextLogger</span><span>.</span><span>logMessage</span><span>(</span><span>level</span><span>,</span> <span>message</span><span>);</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>abstract</span> <span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>);</span>
<span>}</span>
<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>

<span>public</span> <span>abstract</span> <span>class</span> <span>AbstractLogger</span><span>{</span>
    <span>/** * TRACE < DEBUG < INFO < WARN < ERROR < FATAL * which means if the level is INFO, then INFO, WARN, ERROR and FATAL messages will be logged * but if the level is ERROR then only ERROR and FATAL messages will be logged */</span>
    <span>//higher the number higher the priority</span>
    <span>public</span> <span>static</span> <span>int</span> <span>DEBUG</span> <span>=</span> <span>1</span><span>;</span>
    <span>public</span> <span>static</span> <span>int</span> <span>INFO</span> <span>=</span> <span>2</span><span>;</span>
    <span>public</span> <span>static</span> <span>int</span> <span>ERROR</span> <span>=</span> <span>3</span><span>;</span>
    <span>protected</span> <span>int</span> <span>LEVEL</span><span>;</span>
    <span>//next Logger in the chain of responsibility</span>
    <span>private</span> <span>AbstractLogger</span> <span>nextLogger</span><span>;</span>
    <span>public</span> <span>void</span> <span>setNextLogger</span><span>(</span><span>AbstractLogger</span> <span>logger</span><span>){</span>
        <span>this</span><span>.</span><span>nextLogger</span> <span>=</span> <span>logger</span><span>;</span>
    <span>}</span>
    <span>public</span> <span>void</span> <span>logMessage</span><span>(</span><span>int</span> <span>level</span><span>,</span> <span>String</span> <span>message</span><span>){</span>
        <span>//If the logging level of the message is greater than the current Logger's LEVEL then it will be logged </span>
        <span>//example if level = ERROR and this.LEVEL = INFO then the message will be logged as INFO has a lower priority than ERROR</span>
        <span>if</span><span>(</span><span>this</span><span>.</span><span>LEVEL</span> <span><=</span><span>level</span><span>){</span>
            <span>write</span><span>(</span><span>message</span><span>);</span>
        <span>}</span>
        <span>// else the message/request will be passed down to the next logger/object in the chain</span>
        <span>else</span><span>{</span>
            <span>if</span><span>(</span><span>nextLogger</span><span>!=</span><span>null</span><span>){</span>
                <span>nextLogger</span><span>.</span><span>logMessage</span><span>(</span><span>level</span><span>,</span> <span>message</span><span>);</span>
            <span>}</span>
        <span>}</span>
    <span>}</span>
    <span>abstract</span> <span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>);</span>
<span>}</span>
package Patterns.Behavioral.chainOfResponsibility; public abstract class AbstractLogger{ /** * TRACE < DEBUG < INFO < WARN < ERROR < FATAL * which means if the level is INFO, then INFO, WARN, ERROR and FATAL messages will be logged * but if the level is ERROR then only ERROR and FATAL messages will be logged */ //higher the number higher the priority public static int DEBUG = 1; public static int INFO = 2; public static int ERROR = 3; protected int LEVEL; //next Logger in the chain of responsibility private AbstractLogger nextLogger; public void setNextLogger(AbstractLogger logger){ this.nextLogger = logger; } public void logMessage(int level, String message){ //If the logging level of the message is greater than the current Logger's LEVEL then it will be logged //example if level = ERROR and this.LEVEL = INFO then the message will be logged as INFO has a lower priority than ERROR if(this.LEVEL <=level){ write(message); } // else the message/request will be passed down to the next logger/object in the chain else{ if(nextLogger!=null){ nextLogger.logMessage(level, message); } } } abstract void write(String message); }

Enter fullscreen mode Exit fullscreen mode

ConcreteLoggers

<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>
<span>public</span> <span>class</span> <span>DebugLogger</span> <span>extends</span> <span>AbstractLogger</span> <span>{</span>
<span>private</span> <span>String</span> <span>className</span> <span>=</span> <span>this</span><span>.</span><span>getClass</span><span>().</span><span>getSimpleName</span><span>();</span>
<span>private</span> <span>String</span> <span>logger</span> <span>=</span> <span>"DEBUG"</span><span>;</span>
<span>public</span> <span>DebugLogger</span><span>(){</span>
<span>this</span><span>.</span><span>LEVEL</span> <span>=</span> <span>1</span><span>;</span>
<span>}</span>
<span>@Override</span>
<span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>)</span> <span>{</span>
<span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>className</span><span>+</span><span>":"</span><span>+</span><span>logger</span><span>+</span><span>":"</span><span>+</span><span>message</span><span>);</span>
<span>}</span>
<span>}</span>
<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>
<span>public</span> <span>class</span> <span>InfoLogger</span> <span>extends</span> <span>AbstractLogger</span> <span>{</span>
<span>private</span> <span>String</span> <span>className</span> <span>=</span> <span>this</span><span>.</span><span>getClass</span><span>().</span><span>getSimpleName</span><span>();</span>
<span>private</span> <span>String</span> <span>logger</span> <span>=</span> <span>"INFO"</span><span>;</span>
<span>public</span> <span>InfoLogger</span><span>(){</span>
<span>this</span><span>.</span><span>LEVEL</span> <span>=</span> <span>2</span><span>;</span>
<span>}</span>
<span>@Override</span>
<span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>)</span> <span>{</span>
<span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>className</span><span>+</span><span>":"</span><span>+</span><span>logger</span><span>+</span><span>":"</span><span>+</span><span>message</span><span>);</span>
<span>}</span>
<span>}</span>
<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>
<span>public</span> <span>class</span> <span>ErrorLogger</span> <span>extends</span> <span>AbstractLogger</span> <span>{</span>
<span>private</span> <span>String</span> <span>className</span> <span>=</span> <span>this</span><span>.</span><span>getClass</span><span>().</span><span>getSimpleName</span><span>();</span>
<span>private</span> <span>String</span> <span>logger</span> <span>=</span> <span>"ERROR"</span><span>;</span>
<span>public</span> <span>ErrorLogger</span><span>(){</span>
<span>this</span><span>.</span><span>LEVEL</span> <span>=</span> <span>3</span><span>;</span>
<span>}</span>
<span>@Override</span>
<span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>)</span> <span>{</span>
<span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>className</span><span>+</span><span>":"</span><span>+</span><span>logger</span><span>+</span><span>":"</span><span>+</span><span>message</span><span>);</span>
<span>}</span>
<span>}</span>
<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>

<span>public</span> <span>class</span> <span>DebugLogger</span> <span>extends</span> <span>AbstractLogger</span> <span>{</span>
    <span>private</span> <span>String</span> <span>className</span> <span>=</span> <span>this</span><span>.</span><span>getClass</span><span>().</span><span>getSimpleName</span><span>();</span>
    <span>private</span> <span>String</span> <span>logger</span>   <span>=</span> <span>"DEBUG"</span><span>;</span>
    <span>public</span> <span>DebugLogger</span><span>(){</span>
        <span>this</span><span>.</span><span>LEVEL</span> <span>=</span> <span>1</span><span>;</span>
    <span>}</span>

    <span>@Override</span>
    <span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>)</span> <span>{</span>
        <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>className</span><span>+</span><span>":"</span><span>+</span><span>logger</span><span>+</span><span>":"</span><span>+</span><span>message</span><span>);</span>
    <span>}</span>

<span>}</span>

<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>

<span>public</span> <span>class</span> <span>InfoLogger</span> <span>extends</span> <span>AbstractLogger</span> <span>{</span>
    <span>private</span> <span>String</span> <span>className</span> <span>=</span> <span>this</span><span>.</span><span>getClass</span><span>().</span><span>getSimpleName</span><span>();</span>
    <span>private</span> <span>String</span> <span>logger</span>   <span>=</span> <span>"INFO"</span><span>;</span>
    <span>public</span> <span>InfoLogger</span><span>(){</span>
        <span>this</span><span>.</span><span>LEVEL</span> <span>=</span> <span>2</span><span>;</span>
    <span>}</span>

    <span>@Override</span>
    <span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>)</span> <span>{</span>
        <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>className</span><span>+</span><span>":"</span><span>+</span><span>logger</span><span>+</span><span>":"</span><span>+</span><span>message</span><span>);</span>
    <span>}</span>

<span>}</span>
<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>

<span>public</span> <span>class</span> <span>ErrorLogger</span> <span>extends</span> <span>AbstractLogger</span> <span>{</span>
    <span>private</span> <span>String</span> <span>className</span> <span>=</span> <span>this</span><span>.</span><span>getClass</span><span>().</span><span>getSimpleName</span><span>();</span>
    <span>private</span> <span>String</span> <span>logger</span>   <span>=</span> <span>"ERROR"</span><span>;</span>
    <span>public</span> <span>ErrorLogger</span><span>(){</span>
        <span>this</span><span>.</span><span>LEVEL</span> <span>=</span> <span>3</span><span>;</span>
    <span>}</span>

    <span>@Override</span>
    <span>void</span> <span>write</span><span>(</span><span>String</span> <span>message</span><span>)</span> <span>{</span>
        <span>System</span><span>.</span><span>out</span><span>.</span><span>println</span><span>(</span><span>className</span><span>+</span><span>":"</span><span>+</span><span>logger</span><span>+</span><span>":"</span><span>+</span><span>message</span><span>);</span>
    <span>}</span>

<span>}</span>
package Patterns.Behavioral.chainOfResponsibility; public class DebugLogger extends AbstractLogger { private String className = this.getClass().getSimpleName(); private String logger = "DEBUG"; public DebugLogger(){ this.LEVEL = 1; } @Override void write(String message) { System.out.println(className+":"+logger+":"+message); } } package Patterns.Behavioral.chainOfResponsibility; public class InfoLogger extends AbstractLogger { private String className = this.getClass().getSimpleName(); private String logger = "INFO"; public InfoLogger(){ this.LEVEL = 2; } @Override void write(String message) { System.out.println(className+":"+logger+":"+message); } } package Patterns.Behavioral.chainOfResponsibility; public class ErrorLogger extends AbstractLogger { private String className = this.getClass().getSimpleName(); private String logger = "ERROR"; public ErrorLogger(){ this.LEVEL = 3; } @Override void write(String message) { System.out.println(className+":"+logger+":"+message); } }

Enter fullscreen mode Exit fullscreen mode

Main

<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>
<span>public</span> <span>class</span> <span>Main</span> <span>{</span>
<span>public</span> <span>static</span> <span>AbstractLogger</span> <span>intializeLoggers</span><span>(){</span>
<span>AbstractLogger</span> <span>errorLogger</span> <span>=</span> <span>new</span> <span>ErrorLogger</span><span>();</span> <span>//LEVEL = 3;</span>
<span>AbstractLogger</span> <span>infoLogger</span> <span>=</span> <span>new</span> <span>InfoLogger</span><span>();</span> <span>//LEVEL = 2;</span>
<span>AbstractLogger</span> <span>debugLogger</span> <span>=</span> <span>new</span> <span>DebugLogger</span><span>();</span> <span>// LEVEL = 1;</span>
<span>errorLogger</span><span>.</span><span>setNextLogger</span><span>(</span><span>infoLogger</span><span>);</span>
<span>infoLogger</span><span>.</span><span>setNextLogger</span><span>(</span><span>debugLogger</span><span>);</span>
<span>return</span> <span>errorLogger</span><span>;</span><span>// return the highest priority Logger first</span>
<span>}</span>
<span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span> <span>args</span><span>[]){</span>
<span>// initialize the chain of responsible objects</span>
<span>AbstractLogger</span> <span>logger</span> <span>=</span> <span>intializeLoggers</span><span>();</span>
<span>//pass the request down the responsibility chain</span>
<span>//logging level 3 logger</span>
<span>logger</span><span>.</span><span>logMessage</span><span>(</span><span>3</span><span>,</span> <span>"log this error message"</span><span>);</span>
<span>//loggin level 2 logger</span>
<span>logger</span><span>.</span><span>logMessage</span><span>(</span><span>2</span><span>,</span> <span>"info level log message"</span><span>);</span>
<span>//logging level 1 logger</span>
<span>logger</span><span>.</span><span>logMessage</span><span>(</span><span>1</span><span>,</span> <span>"debug level log message"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>package</span> <span>Patterns.Behavioral.chainOfResponsibility</span><span>;</span>

<span>public</span> <span>class</span> <span>Main</span> <span>{</span>
    <span>public</span> <span>static</span> <span>AbstractLogger</span> <span>intializeLoggers</span><span>(){</span>
        <span>AbstractLogger</span> <span>errorLogger</span> <span>=</span> <span>new</span> <span>ErrorLogger</span><span>();</span> <span>//LEVEL = 3;</span>
        <span>AbstractLogger</span> <span>infoLogger</span> <span>=</span> <span>new</span> <span>InfoLogger</span><span>();</span> <span>//LEVEL = 2;</span>
        <span>AbstractLogger</span> <span>debugLogger</span> <span>=</span> <span>new</span> <span>DebugLogger</span><span>();</span> <span>// LEVEL = 1;</span>
        <span>errorLogger</span><span>.</span><span>setNextLogger</span><span>(</span><span>infoLogger</span><span>);</span>
        <span>infoLogger</span><span>.</span><span>setNextLogger</span><span>(</span><span>debugLogger</span><span>);</span>
        <span>return</span> <span>errorLogger</span><span>;</span><span>// return the highest priority Logger first</span>


    <span>}</span>
    <span>public</span> <span>static</span> <span>void</span> <span>main</span><span>(</span><span>String</span> <span>args</span><span>[]){</span>
        <span>// initialize the chain of responsible objects</span>
        <span>AbstractLogger</span> <span>logger</span>  <span>=</span> <span>intializeLoggers</span><span>();</span>

        <span>//pass the request down the responsibility chain</span>
        <span>//logging level 3 logger</span>
        <span>logger</span><span>.</span><span>logMessage</span><span>(</span><span>3</span><span>,</span> <span>"log this error message"</span><span>);</span>
        <span>//loggin level 2 logger</span>
        <span>logger</span><span>.</span><span>logMessage</span><span>(</span><span>2</span><span>,</span> <span>"info level log message"</span><span>);</span>
        <span>//logging level 1 logger</span>
        <span>logger</span><span>.</span><span>logMessage</span><span>(</span><span>1</span><span>,</span> <span>"debug level log message"</span><span>);</span>
    <span>}</span>
<span>}</span>
package Patterns.Behavioral.chainOfResponsibility; public class Main { public static AbstractLogger intializeLoggers(){ AbstractLogger errorLogger = new ErrorLogger(); //LEVEL = 3; AbstractLogger infoLogger = new InfoLogger(); //LEVEL = 2; AbstractLogger debugLogger = new DebugLogger(); // LEVEL = 1; errorLogger.setNextLogger(infoLogger); infoLogger.setNextLogger(debugLogger); return errorLogger;// return the highest priority Logger first } public static void main(String args[]){ // initialize the chain of responsible objects AbstractLogger logger = intializeLoggers(); //pass the request down the responsibility chain //logging level 3 logger logger.logMessage(3, "log this error message"); //loggin level 2 logger logger.logMessage(2, "info level log message"); //logging level 1 logger logger.logMessage(1, "debug level log message"); } }

Enter fullscreen mode Exit fullscreen mode

Output:

ErrorLogger:ERROR:log this error message
InfoLogger:INFO:info level log message
DebugLogger:DEBUG:debug level log message
ErrorLogger:ERROR:log this error message
InfoLogger:INFO:info level log message
DebugLogger:DEBUG:debug level log message
ErrorLogger:ERROR:log this error message InfoLogger:INFO:info level log message DebugLogger:DEBUG:debug level log message

Enter fullscreen mode Exit fullscreen mode

Key points

  • Follows LSP (The Liskov substitution principle i.e. solid design pattern).
  • Follows SRP of solid principle.
  • Follows OCP of solid principle as we can add more Loggers like trace, fatal, etc without modifying existing code at all.
  • Follows ISP as well.

Behavioural Design Patterns (8 Part Series)

1 Observer
2 Strategy
4 more parts…
3 command
4 Chain of responsibility
5 Mediator
6 Memento
7 Template
8 State

原文链接:Chain of responsibility

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
things never change, we change.
世界并没有变,改变的是我们
评论 抢沙发

请登录后发表评论

    暂无评论内容