构造模式+责任链模式实现链式调用(可以用于参数校验)、涉及值传递和地址传递

参考:https://zhuanlan.zhihu.com/p/553917078?utm_id=0
一、责任链模式
责任链模式(Chain of Responsibility Pattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。属于行为型模式。
二、责任链模式的优缺点
1、优点
减少大量ifelse;
逻辑清晰明了,添加删除节点、改变节点顺序方便快捷;
请求与处理解耦;
请求处理者只需关注自己感兴趣的请求,对于不感兴趣的请求,直接转发给下一级节点对象;
易于扩展新的请求处理类,符合开闭原则;
2、缺点
责任链太长或处理时间过长,会影响整体性能。
如果需要判断的东西较多,容易造成类保证;
如果每个判断逻辑较简单,可能会造成一个类只做一个小小的数值判断,哈哈;
如果节点对象存在循环链接,可能会造成死循环;
三、实践
传统方法

@Data
public class Programmer {
    // 姓名
    private String name;
    // 项目
    private String project;
    // 模块
    private String module;
    // 进度
    private double schedule;
    // 计划完成时间
    private Date completePlanTime;
    // 详细信息
    private String info;
}
public class Check {

    public boolean programmerCheck(Programmer programmer){

        if(!"公众号".equals(programmer.getProject())){
            return false;
        }

        if(!"哪吒编程".equals(programmer.getName())){
            return false;
        }

        if(!programmer.getInfo().equals("公众号哪吒编程,定期分享Java干货,还有不定期的送书活动,包邮到你家,哈哈")){
            return false;
        }

        return true;
    }
}

通过责任链模式重构代码
1、链路抽象类定义
这部分是责任链模式的核心代码,重点在于通过next获取下一个节点。

定义一个抽象方法doHandler供子类去实现,实现不同的业务逻辑

public abstract class Handler<T> {

    protected Handler next;

    private void next(Handler next) {
        this.next = next;
    }

    public abstract boolean doHandler(Programmer programmer);

    public static class Builder<T> {
        private Handler<T> head;
        private Handler<T> tail;

        public Builder<T> addHandler(Handler handler) {
            if (this.head == null) {
                this.head = this.tail = handler;
                return this;
            }
            this.tail.next(handler);
            this.tail = handler;
            return this;
        }

        public Handler<T> build() {
            return this.head;
        }
    }
}

(1)项目名称检验

/**
 * 校验项目名称
 */
public class ProjectHandler extends Handler {

    @Override
    public boolean doHandler(Programmer programmer) {

        if(!"公众号".equals(programmer.getProject())){
            return false;
        }

        if(null == next){
            return true;
        }

        return next.doHandler(programmer);
    }
}

校验名字

/**
 * 校验名字
 */
public class NameHandler extends Handler {

    @Override
    public boolean doHandler(Programmer programmer) {

        if(!"哪吒编程".equals(programmer.getName())){
            return false;
        }

        if(null == next){
            return true;
        }

        return next.doHandler(programmer);
    }
}

校验活动细节

/**
 * 校验活动细节
 */
public class InfoHandler extends Handler {

    @Override
    public boolean doHandler(Programmer programmer) {

        if(!programmer.getInfo().contains("扫描文末二维码,关注公众号哪吒编程,定期分享Java干货,还有不定期的送书活动,包邮到你家")){
            return false;
        }

        if(null == next){
            return true;
        }

        return next.doHandler(programmer);
    }
}

测试

核心代码流程:

调用流程:
(1)new Hadnler.Builder() 构建Builder类对象
(2)addHandler(new ProjectHandler()) 此时this.head为空。this.head 和this.tail的地址指向 new ProjectHandler()的地址
(3)addHandler(new NameHandler()) 此时的this.head不为空,走下面,this.tail.next指向NameHandler。因为(2)的this.head = this.tail,此时的是引用传递,传递的是内存地址。所以内存地址的next为NameHandler,所以this.head的next为NamHandler。然后this.tail的地址指向NameHandler的地址
(4)addHandler(new InfoHandler())此时this.tail指向NameHandler。他的next指向InfoHandler,所以NameHandler的next指向InfoHandler。然后将他指向InfoHandler
(5)build 获得this.head,然后doHandler()处理,里面的next.doHandler调用NameHandler处理,依次.....

补充:值传递和引用传递

在Java中,所有的基本数据类型(如int、float等)都是通过值传递来传递参数的,而对象引用也是通过值传递来传递的。

值传递是指将变量或者参数的值复制一份,然后传递给函数或者方法。这意味着在函数或者方法内部对参数进行修改,不会影响到原始变量的值。当我们传递一个基本数据类型时,实际上是传递了它的副本。例如:

public class Test1 {
    public static void main(String[] args) {
       //测试值传递还是引用传递
        int i = 3;
        System.out.println("i的值为:"+i);  //输出3
        

    }
    public void change(int a){
        a = 10;
    }
}

地址传递是指将对象引用的地址复制一份,然后传递给函数或者方法。这里需要注意的是,在Java中,对象本身并没有直接传递,而是传递了对象的引用。这意味着在函数或者方法内部对对象的修改,会影响到原始对象的状态。例如:

public class Test1 {
    public static void main(String[] args) {
       //测试值传递还是引用传递
        People project = new People();
        project.name = "tom";
        System.out.println("没转变前为:"+project.name);  //输出tom

        change(project);

        System.out.println("转变后为:"+project.name); //输出jerry
    }
    public static void change(People a){
        a.name = "jerry";
    }

    public static class People{
        private String name;
    }
}

在内存分析方面,基本数据类型的值存储在栈内存中,而对象引用存储在栈内存中,而对象本身存储在堆内存中。当一个方法被调用时,它会创建一个新的栈帧来保存方法的局部变量和参数。在值传递中,通过复制值的方式将数据从一个栈帧传递到另一个栈帧。在地址传递中,虽然引用的副本被传递,但是它们仍然指向相同的对象,因此对于对象的修改会影响到原始对象。

总结起来,Java中的值传递是指通过复制值的方式传递参数,而地址传递是指通过复制对象引用的地址来传递参数。对于基本数据类型,值传递不会影响原始值;而对于对象引用,地址传递会影响原始对象的状态。

posted @ 2023-07-06 23:20  spiderMan1-1  阅读(234)  评论(0编辑  收藏  举报