设计模式-责任链模式
废话不多说,直接上文。
责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系, 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。
为了有助于理解,我们还是用烂大街的例子,请假。
在学校,你作为食物链最底层(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<Object> { public void doMatch(MaterialMatchContext materialContext, MatchChain matchChain) throws MtrlMatchException; }
//有序匹配 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 List<MtrlMatcher> matchers; private int index = 0; public MatchChainImpl(List<MtrlMatcher> 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<MatchChain>, ApplicationContextAware, InitializingBean { private static final Logger logger = LoggerFactory.getLogger(MatchChainFactoryBean.class); private ApplicationContext applicationContext; //数组形式的责任链,他通过一个index来驱动请求向下执行 private List<MtrlMatcher> 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<MtrlMatcher>(); Map<String, ComparableMatcher> matcherInstanceMap = applicationContext.getBeansOfType(ComparableMatcher.class); if (matcherInstanceMap != null && !matcherInstanceMap.isEmpty()) { for (Entry<String, ComparableMatcher> matcher : matcherInstanceMap.entrySet()) { matchers.add(matcher.getValue()); } } } }
这里通过priority来确定匹配器的使用,决定哪个跳过,那个执行;index则是用来驱动请求向下执行。
当今应用:Dubbo、Mybatis对责任链模式都有不同实现手段,有兴趣可以去了解下。