欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java设计模式(实战)-责任链模式

程序员文章站 2022-03-21 14:41:37
目录一:模式说明二:项目实战三:源代码一:模式说明模式定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止...

一:模式说明

模式定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果(取自《设计模式之禅》)。

翻译:client对象调用一个处理者(类)的方法,可能有多个处理者(实现类),但是该对象只需要调用第一个处理者(类)即可,该模式会自动分配谁来处理这个请求;这多个处理者继承同一个父类(即在一条链上)。

通用类图如下:

java设计模式(实战)-责任链模式

client发送请求到handler,handler自动分配请求到子类的实现类concretehandler中。

二:项目实战

在文章 >手写redis@cacheable注解 支持过期时间设置< 的基础之上做修改,原版为redis缓存注解实现,

原版实现功能:

  • 将数据存放到redis中 
  • 设置过期时间  

原业务逻辑查询人员列表listleader()接口,数据存放redis中,减少数据库负载。

由于业务发展,需要进一步优化查询接口;目前每个人都会操作redis中存放的人员列表,导致该列表会实时发生变动(比如

每个人员对应的分数),每个人都有自己的缓存人员列表而不是统一的人员列表;原列表已经无法满足现需求,每个人第一次登

录都会查询数据库,将自己的列表存放在redis中。

解决方法:设置两级缓存,第一级为该用户(uuid)唯一缓存,key值设置为参数1+uuid+参数2;第二级为第一次登录查询返  

回redis中的原始leader列表,key值设置为参数1+参数2。如果当前用户leader列表(一级缓存)为空,则查询原始leader列表

(二级缓存),在操作分数的时候修改二级缓存(初始人员列表)来产生一级缓存,存放进redis,减少了数据库的直接访问。

项目中责任链相关设计类图如下:

java设计模式(实战)-责任链模式

说明:抽象类cachehandler 一是定义了处理请求方法handlemessage;二是定义一个链的编排方法setnext,设置下一个处理者;三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别gethandlerlevel和具体的处理任务response;

firstcachehadler为一级缓存处理者,secondcachehadler为二级缓存处理者。缓存处理的方式通过cacheableaspect类调用。

三:源代码

cacheableaspect:client调用

package com.huajie.aspect; 
import java.lang.reflect.method;
import java.util.arraylist;
import java.util.list;
import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.pointcut;
import org.aspectj.lang.reflect.methodsignature;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
import com.huajie.annotation.extcacheable;
import com.huajie.common.cache.cachehandler;
import com.huajie.common.cache.firstcachehadler;
import com.huajie.common.cache.redisresult;
import com.huajie.common.cache.secondcachehadler;
import com.huajie.utils.redisutil;
import com.huajie.utils.stringutil;
 
/**
 * redis缓存处理 不适用与内部方法调用(this.)或者private
 */
@component
@aspect
public class cacheableaspect {
 
	@autowired
	private redisutil redisutil;
 
	@pointcut("@annotation(com.huajie.annotation.extcacheable)")
	public void annotationpointcut() {
	}
 
	@around("annotationpointcut()")
	public object doaround(proceedingjoinpoint joinpoint) throws throwable {
		// 获得当前访问的class
		class<?> classname = joinpoint.gettarget().getclass();
		// 获得访问的方法名
		string methodname = joinpoint.getsignature().getname();
		// 得到方法的参数的类型
		class<?>[] argclass = ((methodsignature) joinpoint.getsignature()).getparametertypes();
		object[] args = joinpoint.getargs();
		string key = "";
		string nextkey = "";
		int expiretime = 1800;
		try {
			// 得到访问的方法对象
			method method = classname.getmethod(methodname, argclass);
			method.setaccessible(true);
			// 判断是否存在@extcacheable注解
			if (method.isannotationpresent(extcacheable.class)) {
				extcacheable annotation = method.getannotation(extcacheable.class);
				key = getrediskey(args, annotation.key());
				nextkey = getrediskey(args,annotation.nextkey());
				expiretime = getexpiretime(annotation);
			}
		} catch (exception e) {
			throw new runtimeexception("redis缓存注解参数异常", e);
		}
		//责任链模式
		cachehandler firstcachehadler = new firstcachehadler();
		cachehandler secondcachehadler = new secondcachehadler();
		//设置下级处理者
		firstcachehadler.setnext(secondcachehadler);
		//获取处理级别
		int cachelevel = getcachelevel(key, nextkey);
		redisresult result = new redisresult(redisutil, key, nextkey, joinpoint, cachelevel, expiretime);
		//客户端调用
		return firstcachehadler.handlemessage(result);
	}
 
	private int getcachelevel(string key, string nextkey) {
		if (stringutil.isnotempty(key) && stringutil.isnotempty(nextkey)) {
			return 2;
		} else {
			return 1;
		}
	}
 
	private int getexpiretime(extcacheable annotation) {
		return annotation.expiretime();
	}
 
	private string getrediskey(object[] args, string primalkey) {
		// 获取#p0...集合
		list<string> keylist = getkeyparslist(primalkey);
		for (string keyname : keylist) {
			int keyindex = integer.parseint(keyname.tolowercase().replace("#p", ""));
			object parvalue = args[keyindex];
			primalkey = primalkey.replace(keyname, string.valueof(parvalue));
		}
		return primalkey.replace("+", "").replace("'", "");
	}
 
	// 获取key中#p0中的参数名称
	private static list<string> getkeyparslist(string key) {
		list<string> listpar = new arraylist<string>();
		if (key.indexof("#") >= 0) {
			int plusindex = key.substring(key.indexof("#")).indexof("+");
			int indexnext = 0;
			string parname = "";
			int indexpre = key.indexof("#");
			if (plusindex > 0) {
				indexnext = key.indexof("#") + key.substring(key.indexof("#")).indexof("+");
				parname = key.substring(indexpre, indexnext);
			} else {
				parname = key.substring(indexpre);
			}
			listpar.add(parname.trim());
			key = key.substring(indexnext + 1);
			if (key.indexof("#") >= 0) {
				listpar.addall(getkeyparslist(key));
			}
		}
		return listpar;
	} 
}

cachehandler:

package com.huajie.common.cache;
/**
 * @author xiewenfeng 缓存处理接口
 * 责任链模式
 */
public abstract class cachehandler {
	// 定义处理级别
	protected final static int firstcache_level_request = 1;
	protected final static int secondcache_level_request = 2;
 
	// 能处理的级别
	private int level = 0;
	// 责任传递,下一个责任人是谁
	private cachehandler nexthandler;
 
	// 每个类自己能处理那些请求
	public cachehandler(int level) {
		this.level = level;
	}
 
	// 处理请求
	public final object handlemessage(redisresult redisresult) throws throwable {
		//如果women类型为当前处理的level
		if(redisresult.getcachelevel()==this.level){
			return this.response(redisresult);
		}else{
			 if(null!=this.nexthandler){
				 return this.nexthandler.handlemessage(redisresult);
			 }else{
				 //没有下级不处理
				 return null;
			 }
		}
	}
 
	public void setnext(cachehandler handler) {
		this.nexthandler = handler;
	}
 
	// 有请示的回应
	protected abstract object response(redisresult redisresult) throws throwable;
}

firstcachehadler:一级缓存处理者

package com.huajie.common.cache; 
import org.aspectj.lang.proceedingjoinpoint;
import com.huajie.utils.redisutil; 
public class firstcachehadler extends cachehandler{ 
	public firstcachehadler() {
		super(cachehandler.firstcache_level_request);
	}
 
	@override
	protected object response(redisresult redisresult) throws throwable {
		string key = redisresult.getkey();
		redisutil redisutil = redisresult.getredisutil();
		boolean  haskey = redisutil.haskey(key);
		proceedingjoinpoint joinpoint = redisresult.getjoinpoint();
		int expiretime = redisresult.getexpiretime();
		if (haskey) {
			return redisutil.get(key);
		} else {
			object res = joinpoint.proceed();
			redisutil.set(key, res);
			redisutil.expire(key, expiretime);
			return res;
		}
	} 
}

secondcachehadler:二级缓存处理者

package com.huajie.common.cache; 
import org.aspectj.lang.proceedingjoinpoint;
import com.huajie.utils.redisutil; 
public class secondcachehadler extends cachehandler { 
	public secondcachehadler() {
		super(cachehandler.secondcache_level_request);
	}
 
	@override
	protected object response(redisresult redisresult) throws throwable {
		string nextkey = redisresult.getnextkey();
		string key = redisresult.getkey();
		redisutil redisutil = redisresult.getredisutil();
		proceedingjoinpoint joinpoint = redisresult.getjoinpoint();
		int expiretime = redisresult.getexpiretime();
		boolean haskey = redisutil.haskey(key);
		if (haskey) {
			return redisutil.get(key);
		} else {
			boolean hasnextkey = redisutil.haskey(nextkey);
			if (hasnextkey) {
				return redisutil.get(nextkey);
			} else {
				object res = joinpoint.proceed();
				redisutil.set(nextkey, res);
				redisutil.expire(nextkey, expiretime);
				return res;
			}
		}
	}
}

redisresult:该业务场景对象,用于传递参数

package com.huajie.common.cache; 
import org.aspectj.lang.proceedingjoinpoint;
import com.huajie.utils.redisutil;
import lombok.data;
 
@data
public class redisresult implements iredisresult {
	private int cachelevel;
	private object result;
	private redisutil redisutil;
	private string key;
	private string nextkey;
	private int expiretime;
	private proceedingjoinpoint joinpoint;
 
	@override
	public int getcachelevel() {
		return cachelevel;
	}
 
	@override
	public object getresult() {
		return result;
	}
 
	public redisresult(redisutil redisutil, string key, string nextkey, proceedingjoinpoint joinpoint, int cachelevel,int expiretime) {
		this.redisutil = redisutil;
		this.key = key;
		this.joinpoint = joinpoint;
		this.cachelevel = cachelevel;
		this.nextkey = nextkey;
		this.expiretime = expiretime;
	} 
}

使用方法如下:

@override
	@extcacheable(key = "middle+#p0+#p1+#p2", nextkey = "middle+#p0+#p2")
	public list<middlemanage> listmiddlemanageinfo(string leadergroupid, string uuid, string yeardetailid) {
		map<string, object> map = new hashmap<string, object>();
		map.put("leadergroupid", leadergroupid);
		map.put("uuid", uuid);
		map.put("yeardetailid", yeardetailid);
		list<middlemanage> middlemanagedetaillist = middlemanagemapper.listmiddlemanageinfo(map);
		return middlemanagedetaillist;
	}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。