学习设计模式——责任链模式

本文所有源代码都在我的Github,并且持续更新中…欢迎Star DesignPattern

示例代码

假设我现在有个事件需要上交给政府处理,但是不可能所有小到街坊吵架的事件都交给国家处理,也不可能
大到南水北运的事件交给市级政府处理。所以最先想到用下面的代码来模拟这个情形:

模拟事件类型

public class Event {

    public int eventType = -1;

    public String eventDetail;
    public Event(int eventType,String eventDetail) {

        this.eventType = eventType;
        this.eventDetail = eventDetail;
    }


    @Override
    public String toString() {
        return "Event{" +
                "eventType=" + eventType +
                ", eventDetail='" + eventDetail + '\'' +
                '}';
    }
}

处理单位接口


public interface Handler {

    int COUNTRY_EVENT = 0;
    int PROVINCE_EVENT = 1;
    int CITY_EVENT = 2;


    void process(Event event);

}

市级单位处理类

public class City implements Handler{


    @Override
    public void process(Event event) {
        System.out.println(event);
        System.out.println("我来处理这个市级事件");
    }
}

省级单位处理类



public class Province implements Handler{


    @Override
    public void process(Event event){
        System.out.println(event);
        System.out.println("我来处理这个省份事件");
    }
}

国家单位处理类

public class Country implements Handler {


    @Override
    public void process(Event event) {

        System.out.println(event);
        System.out.println("我来处理这个国家大事");
    }
}

运行类

public class Main {
    public static void main(String[] args) {

        Event event = new Event(Handler.CITY_EVENT, "街区拆迁");


        City city = new City();
        Province province = new Province();
        Country country = new Country();

        switch (event.eventType) {
            case Handler.CITY_EVENT:
                city.process(event);
                break;
            case Handler.PROVINCE_EVENT:
                province.process(event);
                break;

            case Handler.COUNTRY_EVENT:
                province.process(event);
                break;
            default:
                System.out.println("事件飞往火星处理");
                break;


        }

    }

}

这可能是大多数人最先想到的方法,用switch 或者 if..else来判断,但是如果条件一多比如上面的如果再来个区级事件处理类,村级事件处理类,
过多地if..else或者switch会让代码过于臃肿而可读性差。并且这样的格式也造成耦合过重的情况。并且如果一个省级的事件被转交给了市级单位,
正确的做法应该是由市级单位转交给省级单位处理,而在上面的代码却没表现出来。针对上面的情形,我们可以使用责任链模式来
模拟这一切操作。

责任链模式定义

责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也
知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。直到其中一个对象处理该事件。处理事件后处理停止。该模式还描述了往该处理链的末尾添加新的处理对象的方法。

通用源代码

解决方案

我们将Country和Province和City继承Handler,然后把所有的处理类对象用next相连起来,Handler中的handleEvent方法根据事件的类型进行分派给对应的处理对象,
相当于while循环遍历一个链表。具体代码如下:

public abstract class Handler {

    public static final int COUNTRY_EVENT = 0;
    public static final int PROVINCE_EVENT = 1;
    public static final int CITY_EVENT = 2;

    public int processType = -1; //能处理的事件的类型

    public Handler next = null; //下一个处理类


    /**
     * 事件分发给合适的处理单位
     * @param event
     */
    public void handleEvent(Event event) {

        if (event.eventType == this.processType) {
            process(event);

        } else {
            if (next == null) {
                System.out.println("没有能处理的,自行解决吧");
            } else {

                next.handleEvent(event);
            }
        }


    }


    /**
     *
     *
     * @param handler 注入的next
     * @return 注入的next
     */
    public Handler setNext(Handler handler){
        this.next = handler;
        return this.next;
    }
    abstract void process(Event event);

}

市级单位处理类


public class City extends Handler {

    public City(int processType) {
        this.processType = this.processType;

    }

    @Override
    public void process(Event event) {
        System.out.println(event);
        System.out.println("我来处理这个市级事件");
    }
}

省级单位处理类

public class Province extends Handler {


    public Province(int processType) {
        this.processType = processType;
    }

    @Override
    public void process(Event event){
        System.out.println(event);
        System.out.println("我来处理这个省份事件");
    }
}


国家级单位处理类

public class Country extends Handler {

    public Country(int processType) {
        this.processType = this.processType;

    }

    @Override
    public void process(Event event) {

        System.out.println(event);
        System.out.println("我来处理这个国家大事");
    }
}

Country和City、Province这三个类都继承了Handler,并且实现各自的process方法处理相应等级的事件。
最后是我们的Main类:

public class Main {
    public static void main(String[] args) {
        Handler city = new City(Handler.CITY_EVENT);
        city.setNext(new Province(Handler.PROVINCE_EVENT)).setNext(new Country(Handler.COUNTRY_EVENT));

        Event event = new Event(Handler.PROVINCE_EVENT,"城市改名");
        city.handleEvent(event);

        Event event1 = new Event(10,"火星移民");

        city.handleEvent(event1);



    }

}

可以看到我们用setNext设置的访问顺序是City、Province、Country,然后将对于无论什么类型的事件都用City.handleEvent()来处理
这个事件,因为不是对应能处理的类就会继续往下传递,直到无法处理。而且Handler抽象类的子类可以继续增加下去,只需要扩展传递链而已,调用类可以不用了解变化过程, 甚至是谁在处理这个请求都不用知道。

责任链模式优缺点

优点:
* 将请求和处理分开,请求者可以不用知道具体的处理类。
* 降低耦合度,增加新的处理类很简单。

缺点:

  • 每一次处理都要遍历,责任链太长会导致性能受到影响。
  • 调试比较麻烦

适用场景

  • 想分离一个请求的发送者和接收者
  • 在处理对象不多,在运行时根据请求类型动态分派。
  • 不想在代码中明确指定处理程序

注意事项

  • 链中只有一个对象处理请求
  • 有些请求可能无法处理
  • 处理链不能过长,影响性能

现有案例

某些限制是针对典型的责任链模式的。在实践中,这些规则是可以改变的,例如,servlet过滤器是一个责任链实现,它允许多个过滤器处理
HTTP请求。
除此之外还有SpringMVC的拦截器以及Tomcat的Pipeline管道处理。他们都允许多个处理对象处理同一个请求。

参考

维基百科

Follow the Chain of Responsibility

<<设计模式之禅>>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值