设计模式-责任链模式
先简单写下自己看过一些介绍之后,对它的简单理解吧:
就是在进行核心业务逻辑之前,会存在一些前置条件(或处理步骤),而如果此时我们要增加流程(或修改),就会对代码的逻辑侵入修改较大,就可以采取链式调用前面的处理步骤,把耦合降至最低?
责任链定义
责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止
- 链上的每个对象都有机会处理请求
- 链上的每个对象都持有下一个要处理对象的引用
- 链上的某个对象无法处理当前请求,那么它会把相同的请求传给下一个对象
类比:打客服电话前面所走的流程,机器人可以解决的就直接解决,无法解决的会交给人工处理,同时如果此岗位的人工也无法处理,则会转交给其他部门的人工处理
使用场景
- 当必须按顺序执行多个处理者时,可以使用该模式,无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者
- 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式,该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求
- 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序(暂时没有深刻的理解)
不采用责任链的话
此处参考1.代码范例了
在学习前面需要完成洗脸、洗头、吃早餐等等处理步骤
@Data
public class PreparationList {
/**
* 是否洗脸
*/
private boolean washFace;
/**
* 是否洗头
*/
private boolean washHair;
/**
* 是否吃早餐
*/
private boolean haveBreakfast;
}
study类
public class Study {
//不采取责任链的话,就只能采用 if 进行冗余判断
public void study(PreparationList preparationList) {
if (preparationList.isWashHair()) {
System.out.println("洗脸");
}
if (preparationList.isWashHair()) {
System.out.println("洗头");
}
if (preparationList.isHaveBreakfast()) {
System.out.println("吃早餐");
}
System.out.println("我可以去上学了!");
}
}
从上面代码就可以看出,当我们想要增加「刷牙」流程时,需要修改的代码较多,或者想要调换洗脸和洗头的顺序时,也需要调整代码判断顺序
违背开闭原则,即当我们扩展功能的时候需要去修改主流程,无法做到对修改关闭、对扩展开放
采用责任链
特点:链上的每个对象都持有下一个对象的引用
抽象出AbstractPrepareFilter类
public abstract class AbstractPrepareFilter {
//下一个对象的引用
private AbstractPrepareFilter nextPrepareFilter;
public AbstractPrepareFilter(AbstractPrepareFilter nextPrepareFilter) {
this.nextPrepareFilter = nextPrepareFilter;
}
public void doFilter(PreparationList preparationList, Study study) {
//调用准备工作
prepare(preparationList);
//如果没有了下一个对象的引用,则调用 核心业务
if (nextPrepareFilter == null) {
study.study();
} else {
//如果还有下一个对象的引用,继续交给下一个对象处理
nextPrepareFilter.doFilter(preparationList, study);
}
}
public abstract void prepare(PreparationList preparationList);
}
实现抽象类
//洗脸的流程
public class WashFaceFilter extends AbstractPrepareFilter {
public WashFaceFilter(AbstractPrepareFilter nextPrepareFilter) {
//父类的构造函数
super(nextPrepareFilter);
}
@Override
public void prepare(PreparationList preparationList) {
//处理流程
if (preparationList.isWashFace()) {
System.out.println("洗脸");
}
}
}
//洗头
public class WashHairFilter extends AbstractPrepareFilter {
public WashHairFilter(AbstractPrepareFilter nextPrepareFilter) {
super(nextPrepareFilter);
}
@Override
public void prepare(PreparationList preparationList) {
if (preparationList.isWashHair()) {
System.out.println("洗头");
}
}
}
//吃早餐
public class HaveBreakfastFilter extends AbstractPrepareFilter {
public HaveBreakfastFilter(AbstractPrepareFilter nextPrepareFilter) {
super(nextPrepareFilter);
}
@Override
public void prepare(PreparationList preparationList) {
if (preparationList.isHaveBreakfast()) {
System.out.println("吃早餐");
}
}
}
调用方法
@Test
public void testResponsibility() {
PreparationList preparationList = new PreparationList();
preparationList.setWashFace(true);
preparationList.setWashHair(false);
preparationList.setHaveBreakfast(true);
Study study = new Study();
AbstractPrepareFilter haveBreakfastFilter = new HaveBreakfastFilter(null);
AbstractPrepareFilter washFaceFilter = new WashFaceFilter(haveBreakfastFilter);
AbstractPrepareFilter washHairFilter = new WashHairFilter(washFaceFilter);
washHairFilter.doFilter(preparationList, study);
}
以后再去修改流程的时候,就不需要再去修改 study 核心业务了
但是调用的时候,需要调用最开始的 Filter ,对客户不友好
升级版责任链
这里没有采用参考1.的方法,而是结合springboot自动注入的特性,进行了结合
/**
* 处理器接口
*/
public interface Handler {
void setNextHandler(Handler handler);
void handleCheck(User user);
}
实现
//吃早餐
@Component
public class HaveBreakfastHandler implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
@Override
public void handleCheck(User user) {
if(user.isBreakfast()){
System.out.println("吃早饭了");
//如果后续还有引用,继续调用
if(nextHandler != null){
nextHandler.handleCheck(user);
}
}
}
}
@Component
public class WashHairHandler implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
@Override
public void handleCheck(User user) {
if(user.isWashFire()){
System.out.println("洗头了");
//如果后续还有引用,继续调用
if(nextHandler != null){
nextHandler.handleCheck(user);
}
}
}
}
@Component
public class WashFaceHandler implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
@Override
public void handleCheck(User user) {
if(user.isWashFace()){
System.out.println("洗脸了");
//如果后续还有引用,继续调用
if(nextHandler != null){
nextHandler.handleCheck(user);
}
}
}
}
核心代码,也进行一个实现,不过不调用后续链
@Component
public class Study implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
@Override
public void handleCheck(User user) {
//调用核心代码
if(nextHandler == null){
study();
}
}
private void study() {
System.out.println("可以上学了");
}
}
配置责任链
@Configuration
public class ChainConfiguration {
/**
* 配置责任链
* @param haveBreakfastHandler 吃早餐
* @param washFaceHandler 洗脸
* @param washHairHandler 洗头
* @param study 核心代码
* @return 链开头的处理者
*/
@Bean
public Handler chain(HaveBreakfastHandler haveBreakfastHandler,
WashFaceHandler washFaceHandler,
WashHairHandler washHairHandler,
Study study) {
//洗头 -> 洗脸 -> 吃早餐
washHairHandler.setNextHandler(washFaceHandler);
washFaceHandler.setNextHandler(haveBreakfastHandler);
haveBreakfastHandler.setNextHandler(study);
//返回最开始的处理流程
return washHairHandler;
}
}
调用
@SpringBootApplication
public class ChainApplication implements CommandLineRunner {
@Autowired
private Handler chain;
public static void main(String[] args) {
SpringApplication.run(ChainApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
User user = new User();
chain.handleCheck(user);
}
}
洗头了
洗脸了
吃早饭了
可以上学了