由某公司的面试小题目说起,对责任链模式的总结
大企业的面试笔试,往往是非常科学的,尽管有很多哥们会觉着XX企业的招聘程序如同老太太的裹脚布--又臭又长,也可能我是从一个小公司出来的,没怎么见过世面,但仔细考虑一下XX的每一个环节,都是有非常多的亮点的。一个很简单的例子,有一个描述自己工作风格的题目是否符合自己,其中有一个选项我印象特别清楚,“不会因为别人的批评而影响自己的情绪”,这个看起来是褒义的描述,其实是万万不能选的。一个人对别人的批评“无动于衷”的程度越高,这个人能力晋升的空间就越窄!诸如此类的机关比比即是,其实还是蛮享受这次应聘经历的。
有的时候也挺担心本地企业的,一家强势强企业入驻,发个招聘简历,就有上千三年以上工作经验的各个行业的“英才”同胞们一同去应聘。三到五年,无论在什么行业,都应该成为了“一个熟手”,都应该是刚刚可以承担更多更重要责任,为公司的前期培养开花结果的时期,面对更好的平台,大家不约而同的选择了提交自己的简历接受挑选,这对本地企业算不算是一个“讽刺”呢?我想问的是,各位本地企业的大佬们,你们究竟想好怎么留住你们的核心人员?骨干人员?核心编程人员?怎么留住必将成为主流人群的80、90后同事了么?
有点跑题了,继续回到当时面试的那个题目上来,仅仅是简单描述其中的一个需求点:
1)整个系统由多个菜单构成,每个菜单在展示之后需要等待用户的输入。
2)如果用户输入错误,则菜单显示相应的提示信息,提示用户输入错误,需要重新输入。
3)如果用户输入是正确的,那么就会显示下一个菜单。
3)每个菜单都会完成特定的功能,比如计算、展示。
下面是一个例子:
1、当程序开始的时候,屏幕显示:“请输入AAA,BBB,CCC,DDD,EEE,FFF中的一个”。
1)如果用户输入错误,则显示“输入错误,请按照要求输入:”。
2)如果用户输入正确,显示下一个菜单。
2、屏幕显示“请输入1,2,3中的一个”。
1)如果用户输入除了1,2,3之外的信息,则显示“输入错误,请选择1,2,3其中的一个”。
2)如果用户选择了1,则显示“您已经进入菜单0001”。
3)如果用户选择了2,则显示“您已经进入菜单0002”。
4)如果用户选择了3,则显示“您已经进入菜单0003”。
我个人觉着这个题目有两种思路去分析,第一种是比较低级的,就是利用很多do...while,if...else,switch的方式。第二种是相对比较科学的解决方案,就是利用责任链模式。这仅仅是一个技术问题么?绝对不是的,因为选择了使用分支的方式,后面遇到用户需求变动的情况的时候,可能需要我们的维护人员修改大量的代码,因为程序没有达到“高内聚,低耦合”的要求。但是如果是使用责任链模式,就可以从很大程度上来解决维护时候比较吃力的状况,我们可能只是需要两到三步就可以完成一些常见的修改。换位思考一下,我们的终端用户客服MM,如果我们的攻城狮们能够很快速甚至在几秒钟之内满足您的变动需求,她对这个屌丝程序猿的印象会很坏吗?而且,我们的攻城狮们也有很多的时间陪MM一同享受20多岁美好的青春。
好吧,我们省掉那个比较低级的分支结构,直接进入责任链模式好了,责任链模式在日常生活中的应用还是非常广泛的,例如:大家都玩过的4*100接力;击鼓传花游戏;去政府部门办个啥事情,各个部门之间相互推诿;以及国足和泰国比赛时候的带球传球....类似案例不胜枚举。他们都有什么样子的特点呢?
①责任链模式中,一般都会有一个“信息携带者”,比如4*100接力中的接力棒,比如击鼓传花游戏中的花,比如政府办事中的当事人,比如足球比赛中的足球。
②责任链,是由多个承担责任的主体组成的,比如4*100中的参赛选手,击鼓传花中的游戏者,政府办事中的相关部门,足球比赛中的选手。
③每个责任链的组成成员都具备如下几个选择,是否处理该信息携带者,如何处理该信息携带者,将该信息携带者移交给哪一个责任链组成成员。例如国足踢球,有如下选择:我是否接受队友传给我的球(信息携带者),我是在球上咬一口,还是运球过人(如何处理),玩累了,需要将球传递给泰国队友啊,还是传递给泰国队友啊(下一任责任链成员)。
ok,理清了责任链模式应用的场景,我们就可以对责任链进行一个抽象,如下图所示:
下面,我们就来实现上面的例子,代码如下:
核心Holder类的代码如下:
package com.ziwen.chainOfResponsbilities;
public abstract class Holder {
private Holder nextHolder;
public abstract void doService(InfoCarrier infoCarrier);
public Holder getNextHolder() {
return nextHolder;
}
public void setNextHolder(Holder nextHolder) {
this.nextHolder = nextHolder;
}
}
核心类InfoCarrier 的代码如下:
package com.ziwen.chainOfResponsbilities;
public class InfoCarrier {
private String msg;
private int num;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
主方法,程序入口代码如下:
package com.ziwen.chainOfResponsbilities;
import com.ziwen.chainOfResponsbilities.holderImpl.HolderImpl1;
import com.ziwen.chainOfResponsbilities.holderImpl.HolderImpl2;
import com.ziwen.chainOfResponsbilities.holderImpl.HolderImpl3;
public class MainMethod {
public static void main(String[] args) {
InfoCarrier infoCarrier = new InfoCarrier();
Holder holder1 = new HolderImpl1();
Holder holder2 = new HolderImpl2();
Holder holder3 = new HolderImpl3();
holder1.setNextHolder(holder2);
holder2.setNextHolder(holder3);
holder1.doService(infoCarrier);
}
}
三个责任链抽象方法的实现类如下:
package com.ziwen.chainOfResponsbilities.holderImpl;
import com.ziwen.chainOfResponsbilities.Holder;
import com.ziwen.chainOfResponsbilities.InfoCarrier;
public class HolderImpl1 extends Holder{
@Override
public void doService(InfoCarrier infoCarrier) {
System.out.println("HolderImpl1.......");
if(getNextHolder()!=null){
getNextHolder().doService(infoCarrier);
}
}
}
package com.ziwen.chainOfResponsbilities.holderImpl;
import com.ziwen.chainOfResponsbilities.Holder;
import com.ziwen.chainOfResponsbilities.InfoCarrier;
public class HolderImpl2 extends Holder{
@Override
public void doService(InfoCarrier infoCarrier) {
System.out.println("HolderImpl2.......");
if(getNextHolder()!=null){
getNextHolder().doService(infoCarrier);
}
}
}
package com.ziwen.chainOfResponsbilities.holderImpl;
import com.ziwen.chainOfResponsbilities.Holder;
import com.ziwen.chainOfResponsbilities.InfoCarrier;
public class HolderImpl3 extends Holder{
@Override
public void doService(InfoCarrier infoCarrier) {
System.out.println("HolderImpl3.......");
if(getNextHolder()!=null){
getNextHolder().doService(infoCarrier);
}
}
}
我们在上述责任链模式就可以扩展起来一个比较容易实现“高内聚,低耦合”的上述需求的实现。例如,将main方法中的构造通过xml来保存,使用factory模式来提供相关的控制反转,扩展InfoCarrier类,让其提供更多的例如展示错误信息,展示上一个责任链参与者写入的信息等等。
好的设计模式,是要深入去打磨的,不同的场景下,选择一个合适的设计模式是相当重要的一件事情!