上下文设计模式

上下文模式

概述:在方法的调用链需要一个上下文来贯穿整个调用链,主要通过它来存储数据和传递数据。通常的上下文模式如下所示(下面也给出了ThreadLocal进行上下文的改造):
1.创建ExcutionTask主要用来执行任务

public class ExcutionTask implements Runnable {

    private final QueryForDBAction queryForDBAction = new QueryForDBAction();

    private final HttpQueryAction httpQueryAction = new HttpQueryAction();

    @Override
    public void run() {
        final Context context = new Context();
        //查询名称
        queryForDBAction.execute(context);
        System.out.println(Thread.currentThread().getName()+ "  查询的姓名为: "+context.getName());
        //根据名称查询身份证
        httpQueryAction.execute(context);
        System.out.println(Thread.currentThread().getName() + "  查询的身份证为 " + context.getCardId());

    }
}

2.创建执行的上下文Context。一个完整的请求分为两步,一个向数据库查询数据,一个向http请求数据。数据库查询当前的name,将name作为参数传给http,这里不直接传参而是直接传context上下文,context里存放了name

public class Context {
    private String name;
    private String cardId;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getCardId() {
        return this.cardId;
    }
}

3.创建QueryForDBAction模拟从数据库查询数据

public class QueryForDBAction {

    public void execute(Context context){
        try {
            String name = "zs";
            Thread.sleep(2000);
            context.setName(name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

4.创建HttpQueryAction模拟从网络上获取数据

public class HttpQueryAction {

    public void execute(Context context) {

        try {
            String name = context.getName();
            String cardId = queryCardId(name);
            Thread.sleep(2000);
            context.setCardId(cardId);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public String queryCardId(String name) {
        return "46513498765131";
    }

}

5.测试类编写

public class Application {
    public static void main(String[] args) {
        IntStream.range(1,5).forEach(i ->{
           new Thread(new ExcutionTask()).start();
        });
    }
}

不足与改进

在这里因为ExcutionTask都需要一个上下文context,可以不传参,考虑通过一个类直接获取即可,让每个线程都有自己的context–可以使用ThreadLocal设置默认的context即可。这里的ActionContext可以设置为单例。

这样不需要考虑线程安全性问题

public class ActionContext {
    private static final ThreadLocal<Context> THREAD_LOCAL = new ThreadLocal<Context>(){
        @Override
        protected Context initialValue() {
            return new Context();
        }
    };

    private ActionContext(){

    }
    private static class Inner{
        private static final ActionContext actionContext = new ActionContext();
    }

    public static ActionContext getInstance(){
        return Inner.actionContext;
    }

    public Context getContext(){
        return THREAD_LOCAL.get();
    }
}

这样之前new Context的地方就可以换成使用ActionContext.getInstance.getContext()就可以了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

分析如下

这样在方法调用时因为是同一个线程,这样不需要传递context了,只需要随时用随时getContext()皆可以了,因为ThreadLocal里面同一个线程拿到的Context是同一个。
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值