【デザインパターン】わかりやすい責任連鎖パターン

導入

自動車の製造工程では、エンジン、ギアボックス、ボディなど、自動車のさまざまな部品の厳格な品質検査を実施し、不適格な部品をろ過する必要があります。

自動車部品のフィルター検査

一般に、これは次のように書くことで実行できます。

public class Client {
    public static void main(String[] args) {
        Client client = new Client();

        Request req = new Request();
        req.setReqMsg("检查发动机,变速箱,车身有没有问题");
        if (req.getReqMsg().contains("车身")) {
            client.doCheckCarbody();
        }
        if (req.getReqMsg().contains("发动机")) {
            client.doCheckEngine();
        }
        if (req.getReqMsg().contains("变速箱")) {
            client.doCheckGearbox();
        }
        if (req.getReqMsg().contains("xxx")) {
            // do something
        }
    }

    public void doCheckEngine () {
        System.out.println("------检查了发动机------");
    }

    public void doCheckCarbody () {
        System.out.println("------检查了车身-------");
    }

    public void doCheckGearbox () {
        System.out.println("------检查了变速箱-----");
    }
}

class Request {
    private String reqMsg;

    public String getReqMsg() {
        return reqMsg;
    }

    public void setReqMsg(String reqMsg) {
        this.reqMsg = reqMsg;
    }
}
复制代码

しかし、参照してください

if (req.getReqMsg().contains("xxx")) {
    // do something
}
复制代码

これは?これは、より多くのチェック事項とより多くのifステートメントを意味します(とても馴染みのあるコード、ハハ)

肥大化したものを取り除きif、エレガントに自動車部品の検査を行う方法は?

上記のコードでは、ある日部品が検査から免除された場合、その部品を検査する必要はなく、特定のifブランチを削除する必要があります。現時点では、すべてのコードをリファクタリングするのが待ちきれません。

オブジェクト指向には、カプセル化。これは、どの部分を変更する必要があるか、どの部分をカプセル化できるか、自動車部品を扱う部分をカプセル化できることを意味します。

コードは次のように表示されます。

public class Client {
    public static void main(String[] args) {
        Request req = new Request();
        req.setReqMsg("检查发动机,变速箱,车身有没有问题");

        List<Filter> filters = new ArrayList<>();
        filters.add(new CarbodyFilter());
        filters.add(new GearboxFilter());
        filters.add(new EngineFilter());

        for (Filter f : filters) {
            f.doFilter(req);
        }
    }
}

class Request {
    private String reqMsg;

    public String getReqMsg() {
        return reqMsg;
    }

    public void setReqMsg(String reqMsg) {
        this.reqMsg = reqMsg;
    }
}

interface Filter {
    boolean doFilter(Request request);
}

class EngineFilter implements Filter {
    @Override
    public boolean doFilter(Request request) {
        if (request.getReqMsg().contains("发动机")) {
            System.out.println("------检查了发动机------");
        }
        return true;
    }
}

class GearboxFilter implements Filter {
    @Override
    public boolean doFilter(Request request) {
        if (request.getReqMsg().contains("变速箱")) {
            System.out.println("------检查了变速箱------");
        }
        return true;
    }
}

class CarbodyFilter implements Filter {
    @Override
    public boolean doFilter(Request request) {
        if (request.getReqMsg().contains("车身")) {
            System.out.println("------检查了车身------");
        }
        return true;
    }
}
复制代码

このように、どの部分を確認したい場合は、質問するだけです。

List<Filter> filters = new ArrayList<>();
复制代码

filters追加Filterするだけです。このコードはもう少し面白いですか?

最もエレガントなものはなく、よりエレガントなものだけです

以前のバージョンのコードは、実行するために内部に追加Clientする必要がありますが、これはほとんど意味がありません。List<Filter>Filter

上記のシナリオを見てみましょう。

それぞれが相互にリンクされ、内部で実行される限り、それぞれがFilter独自の義務を果たしますか?Filter

次に、それらをつなぎ合わせるためのaFilterChainを。

class FilterChain implements Filter {
    List<Filter> filters = new ArrayList<>();

    //比较骚的写法,这样可以链式调用
    public FilterChain add(Filter filter) {
        filters.add(filter);
        return this;
    }
    //一般写法
//    public void add(Filter filter) {
//        filters.add(filter);
//    }

    @Override
    public boolean doFilter(Request request) {
        for (Filter f : filters) {
            //任何一环检查出了问题,均不往下检查
            if (!f.doFilter(request)) {
                return false;
            }
        }
        return true;
    }
}
复制代码

FilterChain本文中の方法は次のとおりaddです。まず、一般的な書き込み方法を見てください。

public void add(Filter filter) {
    filters.add(filter);
}
复制代码

次に、呼び出しは次のように実行する必要があります。

FilterChain chain = new FilterChain();
chain.add(new EngineFilter());
chain.add(new GearboxFilter());
chain.add(new CarbodyFilter());
chain.doFilter(req);
复制代码

より生意気な書き方があります:

public FilterChain add(Filter filter) {
    filters.add(filter);
    return this;
}
复制代码

移行:

FilterChain chain = new FilterChain();
chain.add(new EngineFilter())
        .add(new GearboxFilter())
        .add(new CarbodyFilter())
        .doFilter(req);
复制代码

は?私はxxソースコードでこの書き方を見てきました!インスタントアップグレードのように感じました。

上記のFilterChainバージョンは、実際にはChain of Responsibilityモデルです!

似曾相识的FilterChain

没错,如果你开发过Java Web程序,你一定见过这个东西。

比如 ServletFilterStrutsInterceptorSpring MVCHandlerInterceptor 。它们本质上都是过滤器或者叫拦截器。

JavaEE Filter

我用刚才的场景

模拟了一下FilterFilterChain

public class Client {
    public static void main(String[] args) {
        Request request = new Request();
        request.reqMsg = "检查发动机,变速箱,车身有没有问题";
        Response response = new Response();
        response.respMsg = "-------response:";

        FilterChain chain = new FilterChain();
        chain.add(new EngineFilter()).add(new GearboxFilter()).add(new CarbodyFilter());
        chain.doFilter(request, response);

        System.out.println(response.respMsg);
    }
}

class Request {
    String reqMsg;
}

class Response {
    String respMsg;
}

interface Filter {
    void doFilter(Request request, Response response, FilterChain chain);
}

class EngineFilter implements Filter {
    public void doFilter(Request request, Response response, FilterChain chain) {
        //先处理request请求
        if (request.reqMsg.contains("发动机")) {
            System.out.println("------EngineFilter 检查了发动机------");
        }
        //通过链条传递处理下一个request
        chain.doFilter(request, response);
        //处理response
        response.respMsg += "---执行了EngineFilter过滤器---";
    }
}

class GearboxFilter implements Filter {
    public void doFilter(Request request, Response response, FilterChain chain) {
        if (request.reqMsg.contains("变速箱")) {
            System.out.println("------GearboxFilter 检查了变速箱------");
        }
        //通过链条传递处理下一个request
        chain.doFilter(request, response);
        //处理response
        response.respMsg += "---执行了GearboxFilter过滤器---";
    }
}

class CarbodyFilter implements Filter {
    public void doFilter(Request request, Response response, FilterChain chain) {
        if (request.reqMsg.contains("车身")) {
            System.out.println("------CarbodyFilter 检查了车身------");
        }
        //通过链条传递处理下一个request
        chain.doFilter(request, response);
        //处理response
        response.respMsg += "---执行了CarbodyFilter过滤器---";
    }
}

class FilterChain {
    List<Filter> filters = new ArrayList<>();
    int filterIndex = 0;

    public FilterChain add(Filter filter) {
        filters.add(filter);
        return this;
    }

    public void doFilter(Request request, Response response) {
        //如果request链条执行完了,就不往下传递了
        if (filterIndex == filters.size()) {
            return;
        }
        Filter f = filters.get(filterIndex);
        filterIndex++;
        f.doFilter(request, response, this);
    }
}
复制代码

捋一捋:

FilterChain 里面定义了一个 filterIndex 来控制链条顺序执行,并且在每个filter的doFilter里

  1. 先处理request
  2. 调用chain.doFilter(request, response)传递链条
  3. 处理response

看下执行结果:

这些框架的过滤器、拦截器使用的也是 责任链模式

小结

  • 责任链模式 (Chain of Responsibility)是一种 处理请求 的模式,它让多个处理器都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递。
  • 责任链模式在添加新的处理类或者排列处理请求的顺序上非常容易。
  • 拦截、预处理请求等场景下经常会用到责任链模式。

暗示自己:好好学习设计模式,咱也能写出优秀的代码!!!

以上。

点个赞再走吧~

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿

おすすめ

転載: juejin.im/post/7120039388620259359