责任链模式也叫职责链模式,是一种行为型模式。
该模式中将处理请求的对象串成一条链,当有请求发生时,请求会在链上的各个节点(处理对象)传递,直达有对象能够处理它为止,如果不能处理,则继续向后传递直到结束。
百度百科定义:责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
主要角色
抽象处理者(Handler)
定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler)
实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
一个例子
目前需要根据给定的原材料,生产不同的物品。比如,输送进去木头,就会生产出来一把椅子;输送棉花,就会生产出棉布;输送牛奶就会生产出奶酪。
现在要给这个机器编写对应的程序。
/**
* 原材料
* @author: xujian
* @Date: 2019-09-23
* @Description:
*/
public interface Material {
String getName();
}
/**
* 棉花
* @author: xujian
* @Date: 2019-09-23
* @Description:
*/
public class Cotton implements Material {
@Override
public String getName() {
return "棉花";
}
}
/**
* 牛奶
* @author: xujian
* @Date: 2019-09-23
* @Description:
*/
public class Milk implements Material{
@Override
public String getName() {
return "牛奶";
}
}
/**
* 木头
* @author: xujian
* @Date: 2019-09-23
* @Description:
*/
public class Wood implements Material{
@Override
public String getName() {
return "木头";
}
}
public class Glass implements Material {
@Override
public String getName() {
return "玻璃";
}
}
一般做法
最直接的做法就是if-else。
/**
* 机器程序
* @author: xujian
* @Date: 2019-09-23
* @Description:
*/
public class MachineProgram {
public static void produce(Material material) {
if (material instanceof Cotton) {
System.out.println("原材料:棉花,生产出棉布");
} else if (material instanceof Milk) {
System.out.println("原材料:牛奶,生产出奶酪");
} else if (material instanceof Wood) {
System.out.println("原材料:木头,生产出椅子");
}
}
}
开始生产
//生产棉布
Material material = new Cotton();
MachineProgram.produce(material);
//生产牛奶
Material material1 = new Milk();
MachineProgram.produce(material1);
//生产椅子
Material material2 = new Wood();
MachineProgram.produce(material2);
原材料:棉花,生产出棉布
原材料:牛奶,生产出奶酪
原材料:木头,生产出椅子
责任链模式
抽象处理器
public abstract class MaterialProcessor {
private MaterialProcessor processor;
public void process(Material material) {
System.out.println("当前为处理器为:"+this.getProcessName());
if (canProcess(material)) {
doProcess(material);
} else if (Objects.nonNull(processor)) {
System.out.println("切换处理器...");
processor.process(material);
} else {
fail(material);
}
}
abstract void doProcess(Material material);
public void fail(Material material) {
System.out.println("处理结束,"+material.getName()+"不能被处理!");
}
public abstract boolean canProcess(Material material);
public MaterialProcessor setProcessor(MaterialProcessor processor) {
this.processor = processor;
return processor;
}
abstract String getProcessName();
}
具体处理器
public class CottonMaterialProcessor extends MaterialProcessor {
@Override
void doProcess(Material material) {
System.out.println("原材料:棉花,生产出棉布");
}
@Override
public boolean canProcess(Material material) {
return material instanceof Cotton;
}
@Override
String getProcessName() {
return "棉花处理器";
}
}
public class MilkMaterialProcessor extends MaterialProcessor {
@Override
void doProcess(Material material) {
System.out.println("原材料:牛奶,生产出奶酪");
}
@Override
public boolean canProcess(Material material) {
return material instanceof Milk;
}
@Override
String getProcessName() {
return "牛奶处理器";
}
}
public class WoodMaterialProcessor extends MaterialProcessor {
@Override
void doProcess(Material material) {
System.out.println("原材料:木头,生产出椅子");
}
@Override
public boolean canProcess(Material material) {
return material instanceof Wood;
}
@Override
String getProcessName() {
return "木头处理器";
}
}
MaterialProcessor cottonProcessor = new CottonMaterialProcessor();
MaterialProcessor milkProcessor = new MilkMaterialProcessor();
MaterialProcessor woodProcessor = new WoodMaterialProcessor();
cottonProcessor.setProcessor(milkProcessor).setProcessor(woodProcessor);
cottonProcessor.process(new Cotton());
System.out.println("---------------------------");
cottonProcessor.process(new Wood());
System.out.println("---------------------------");
cottonProcessor.process(new Glass());
当前为处理器为:棉花处理器
原材料:棉花,生产出棉布
---------------------------
当前为处理器为:棉花处理器
切换处理器...
当前为处理器为:牛奶处理器
切换处理器...
当前为处理器为:木头处理器
原材料:木头,生产出椅子
---------------------------
当前为处理器为:棉花处理器
切换处理器...
当前为处理器为:牛奶处理器
切换处理器...
当前为处理器为:木头处理器
处理结束,玻璃不能被处理!
总结
- 通过上面的代码,使用责任链以后客户端处理明显简单了,屏蔽了条件判断。
- 通过给予多个对象处理请求的机会,以达到请求发送者和接受者的松散耦合。
- 符合“开闭原则”,新增一个处理器只需要重新建链即可。
- 可能因为职责链创建不当,造成循环调用,导致系统陷入死循环。
- Netty中的Pipline和ChannnelHandler就是用了责任链模式。
- Cas单点登录框架重的FilterChain也是使用了责任链模式。
你可以在这里获取相关代码:设计模式-Chain of Responsibility模式