Java设计模式--责任链模式


概述

在人类社会中,责任链模式是天然存在的,比如在购置房产的社会,购房者会想要一定的折扣,但是根据买的量级的不同,享受的折扣也是不一样的。其实有时候我们会发现假如你认得这个房产公司的经理的话,你享受的折扣可能会比较大,这是为什么呢?因为房产公司是有层级关系的,大致可以分为:CEO->总监->经理->销售员。每个层级能打的折扣是不一样的,如果你不认识人的话,就只能按照你想要的折扣去向销售员申请,假如销售员能给这个折扣就给你了,但是如果没有的话,那就要销售员向上申请,得到上面的反馈以后再回复客户。所有客户是不知道他所想要的折扣是谁给的,最后只能知道这个折扣申请是成功了还是失败了。

概念

责任链模式就是将接收者对象连成一条链,并在该链上传递请求,直到有一个接收者对象处理它。通过让更多对象有机会处理请求,避免了请求发送者和接收者之间的耦合。

Handler后面的successor表示的是由一条链组成,并且持有自己的引用。
ConcreteHandler是Handler的实现类。

责任链模式代码实现

首先我们需要定义一个接口,之后的处理人都要实现这个接口,因为是个链表,使用我们要指定后继,因为Java的多态所以我们只需要使用PriceHandler就好了。
PriceHandler.java

package com.xjh.cor;
/**
 * 价格处理人,负责处理客户的折扣申请
 * 对外暴露的Handler接口
 * @author Gin
 *
 */
public abstract class PriceHandler {

    //直接后继,用于传递请求
    protected PriceHandler successor;

    public void setSuccessor(PriceHandler successor){
        this.successor = successor;
    }

    //处理折扣申请
    public abstract void processDiscount(float discount);

}

之后我们就需要定义一些处理级别
Sales.java

package com.xjh.cor;
/**
 * 销售员,可以批准5%以内的折扣
 * @author Gin
 *
 */
public class Sales extends PriceHandler {

    @Override
    public void processDiscount(float discount) {
        if(discount <= 0.05) {
            System.out.format("%s批准了折扣:%.2f\n", this.getClass().getName(),discount);
        }
        else {
            successor.processDiscount(discount);
        }

    }

}

Manager.java

package com.xjh.cor;
/**
 * 经理,可以批准30%以内的折扣
 * @author Gin
 *
 */
public class Manager extends PriceHandler {

    @Override
    public void processDiscount(float discount) {
        if(discount <= 0.3) {
            System.out.format("%s批准了折扣:%.2f\n", this.getClass().getName(),discount);
        }
        else {
            successor.processDiscount(discount);
        }

    }

}

CEO.java

package com.xjh.cor;
/**
 * CEO,可以批准50%以内的折扣
 * @author Gin
 *
 */
public class CEO extends PriceHandler {

    @Override
    public void processDiscount(float discount) {
        if(discount <= 0.5) {
            System.out.format("%s批准了折扣:%.2f\n", this.getClass().getName(),discount);
        }
        else {
            System.out.format("%s拒绝了折扣:%.2f\n", this.getClass().getName(),discount);
        }

    }

}

然后定义一个顾客类,里面发起申请就好了。
Customer.java

package com.xjh.cor;

public class Customer {

    private PriceHandler pricHandler;

    public void setPriceHandler(PriceHandler pricHandler) {
        this.pricHandler = pricHandler;
    }

    public void requestDiscount(float discount) {
        pricHandler.processDiscount(discount);
    }

}

然后定义一个Main函数来进行调用,当然在申请之前我们需要将各个的处理级别连成链,所以我们创建一个工厂方法来进行这个操作,因为顾客面对的就是销售人员,所以我们返回这个最低级的处理级别就好了。
PriceHandlerFactory.java

package com.xjh.cor;

public class PriceHandlerFactory {

    //创建PriceHandler的工厂函数
    public static PriceHandler createPricHandler() {
        // TODO Auto-generated method stub
        PriceHandler sales= new Sales();
        PriceHandler lead= new Lead();
        PriceHandler manager= new Manager();
        PriceHandler ceo= new CEO();
        sales.setSuccessor(lead);
        lead.setSuccessor(manager);
        manager.setSuccessor(ceo);
        return sales;
    }
}

Test.java

package com.xjh.cor;

import java.util.Random;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Customer customer = new Customer();
        customer.setPriceHandler(PriceHandlerFactory .createPricHandler());
        Random rand = new Random();
        for(int i=0;i<10;i++) {
            System.out.print(i+":");
            customer.requestDiscount(rand.nextFloat());
        }
    }

}

效果就是这样的。

总结

其实我们发现我们的代码中都是使用了PriceHandler这个抽象类,这样我们就方便后面的添加,诠释了依赖倒置原则(不知道可以看我的另一篇博客:传送门),这样就 降低了两者的耦合度。并且因为发出请求的客户端并不知道链上的哪个接收者会处理这个请求,从而实现了客户端和接收者之间的解耦。
如果我们想要增加一个级别,其实对于客户端是不知道了,这样也就表明了耦合度的降低。

优点
  • 实现较为简单,抽象较为容易
  • 低耦合,方便之后的修改
缺点
  • 耗时较长
  • 内存消耗过大,因为较为顶级的处理级别很难被调用,但是不得不进行声明,所以消耗巨大内存。


原文链接:https://blog.csdn.net/xjh_shin/article/details/84980615