废话不多说,直接上文。
责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。
为了有助于理解,我们还是用烂大街的例子,请假。
在学校,你作为食物链最底层(ps:这里有人会说我是xx委员什么的,你这就属于杠精了额),请假情况一般是这样的:先向班长请假,如果班长没权处理就会向老师请,逐级递增,一直到导员,于是,我们角色定义就成了如下:
1.班长(Monitor):可以请假不开会
2.老师(Teacher):可以请假不上课
3.导师(Supervisor):可以请假不上学
附代码:
处理请求的抽象类,具体执行由子类完成
public abstract class Handler { /** * 执行人 */ protected Handler successor; /** * 执行人名称 */ protected String name; /** * 处理请求,由子类完成 * @param request */ public abstract void handleRequest(String request); /** * 设置下一个处理请求的人 * @param successor */ public void setNextHander(Handler successor) { this.successor = successor; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
班长执行请求(班长具有的属性方法:名称、执行方法、执行人(下家)、设置下家)
public class Monitor extends Handler { public Monitor(String name) { this.name = name; } /** * 执行自己有权的请求,无权则给下一个执行 */ @Override public void handleRequest(String request) { if ("请假不开会".equals(request)) { System.out.println(name + "可以处理" + request + ",给予批准!"); } else { System.out.println(name + "不可以处理" + request + "转交给" + successor.getName()); successor.handleRequest(request); } } }
其他角色代码同班长
public class ExecuteChain { public static void main(String[] args) { Handler teacher = new Teacher("老师"); Handler monitor = new Monitor("班长"); Handler supervisor = new Supervisor("导员"); monitor.setNextHander(teacher); teacher.setNextHander(supervisor); monitor.handleRequest("请假不上学"); } }
执行链
工作中应用的例子:
刚毕业那会儿工作有这样一个场景就用了责任链模式,首先我们有一个存着特定数据的excel,现在需要把它解析成我们需要的数据,最终的方案是通过正则和配置文件来匹配,没有匹配就通过搜索引擎lucene查询分词(事先定义好自己的分词),如果还没有匹配到就通过drools规则引擎匹配,其中任何一个通过匹配就结束。
定义如下:
第一层识别:
public class LibraryMaterialMatcher extends ComparableMatcher
{
public LibraryMaterialMatcher()
{
this.priority = 1;
}
@Override
public void doMatchInternal(MaterialMatchContext materialContext, MatchChain matchChain) throws MtrlMatchException
{
...
// 继续链条处理
matchChain.doMatch(materialContext);
}
}
第二层识别:
public class LuceneMaterialMatcher extends ComparableMatcher
{
public LuceneMaterialMatcher()
{
this.priority = 5;
}
@Override
public void doMatchInternal(MaterialMatchContext materialContext, MatchChain matchChain) throws MtrlMatchException
{
...
// 继续链条处理
matchChain.doMatch(materialContext);
}
}
第三层识别:
public class DroolsMaterialMatcher extends ComparableMatcher
{
public DroolsMaterialMatcher()
{
this.priority = 10;
}
@Override
public void doMatchInternal(MaterialMatchContext materialContext, MatchChain matchChain) throws MtrlMatchException
{
...
// 继续链条处理
matchChain.doMatch(materialContext);
}
}
其中父类和接口定义如下:
//物料匹配器 public interface MtrlMatcher extends Comparable
//有序匹配
public abstract class ComparableMatcher implements MtrlMatcher
{
/**
* 匹配器的优先级
*/
protected int priority = -1;
/**
* Matcher 排序
*/
public int compareTo(Object obj)
{
ComparableMatcher otherMatcher = (ComparableMatcher) obj;
int priorityDifference = this.priority - otherMatcher.priority;
return priorityDifference;
}
@Override
public void doMatch(MaterialMatchContext materialContext, MatchChain matchChain) throws MtrlMatchException
{
if (this.getPriority() <= materialContext.getPrioritySkip())
{
matchChain.doMatch(materialContext);
}
else
{
doMatchInternal(materialContext, matchChain);
}
}
/**
* @Description: 子类匹配器具体实现
*/
public abstract void doMatchInternal(MaterialMatchContext materialContext, MatchChain matchChain) throws MtrlMatchException;
public int getPriority()
{
return priority;
}
public void setPriority(int priority)
{
this.priority = priority;
}
}
以上是匹配器的定义,接下来介绍具体调用
//调用匹配链
//由MatchChainFactory创建MatchChain的实现,
MatchChain matchChain = MatchChainFactory.createMatchChain();//这时匹配器已经存在
//设置参数
MaterialMatchContext materialMatchContext = new MaterialMatchContext();
materialMatchContext.setMaterialProject(materialProject);
materialMatchContext.setUserMaterial(userMaterial);
matchChain.doMatch(materialMatchContext);
matchChain.reset();
public interface MatchChain { //匹配方法 public void doMatch(MaterialMatchContext materialContext) throws MtrlMatchException; /** * @Description: 重置过滤器 * @return void */ public void reset(); }
public class MatchChainImpl implements MatchChain { private static final Logger logger = LoggerFactory.getLogger(MatchChainImpl.class); private Listmatchers; private int index = 0; public MatchChainImpl(List matchers) { super(); this.matchers = matchers; this.index = 0; Collections.sort(matchers); } @Override public void doMatch(MaterialMatchContext materialContext) throws MtrlMatchException { if (this.matchers == null || this.matchers.size() == this.index) { if (logger.isDebugEnabled()) { logger.debug(" we've reached the end of the match chain."); } // if you like,you can do something here. } else { if (logger.isDebugEnabled()) { logger.debug("Invoking matcher at index [" + this.index + "]"); }
//向下执行 this.matchers.get(this.index++).doMatch(materialContext, this); } } @Override public void reset() { this.index = 0; } }
public class MatchChainFactory
{
//创建识别过滤器链
public static MatchChain createMatchChain()
{
return ApplicationContextUtil.getBean("matchChainFactoryBean", MatchChain.class);
}
}
@Component public class MatchChainFactoryBean implements FactoryBean, ApplicationContextAware, InitializingBean { private static final Logger logger = LoggerFactory.getLogger(MatchChainFactoryBean.class); private ApplicationContext applicationContext; //数组形式的责任链,他通过一个index来驱动请求向下执行 private List matchers; @Override public MatchChain getObject() throws Exception { if (logger.isDebugEnabled()) { logger.debug("Create MatchChain Instance..."); } return new MatchChainImpl(matchers); } @Override public Class> getObjectType() { return MatchChain.class; } @Override public boolean isSingleton() { return false; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } //添加匹配器 @Override public void afterPropertiesSet() throws Exception { if (logger.isDebugEnabled()) { logger.debug("Create Matcher Instance Map..."); } matchers = new ArrayList (); Map matcherInstanceMap = applicationContext.getBeansOfType(ComparableMatcher.class); if (matcherInstanceMap != null && !matcherInstanceMap.isEmpty()) { for (Entry matcher : matcherInstanceMap.entrySet()) { matchers.add(matcher.getValue()); } } } }
这里通过priority来确定匹配器的使用,决定哪个跳过,那个执行;index则是用来驱动请求向下执行。
当今应用:Dubbo、Mybatis对责任链模式都有不同实现手段,有兴趣可以去了解下。