【设计模式】1,责任链与装饰者模式(基本介绍)
【前言】 本人从事了.net开发近10年,现在从.net转型到java不足2月,所以所见所想都带着很深的.net烙印,不过也有很大可能是java翻译成.net,之后我又给转回java了。
【责任链模式】
外置方式
传统的责任链模式是一个请求有很多处理类,将这些处理类排列成一个顺序数组,如果某一个处理类能够处理,则中止请求;如果不能,则依次继续请求直到全部请求完毕。
用代码表示,就是如下所示:
1 //上下文环境 2 public class context { 3 public string gethandlername() { 4 return handlername; 5 } 6 7 public void sethandlername(string handlername) { 8 this.handlername = handlername; 9 } 10 11 public string gethandlerresult() { 12 return handlerresult; 13 } 14 15 public void sethandlerresult(string handlerresult) { 16 this.handlerresult = handlerresult; 17 } 18 19 public boolean ishashandled() { 20 return hashandled; 21 } 22 23 public void sethashandled(boolean hashandled) { 24 this.hashandled = hashandled; 25 } 26 27 string handlername; 28 29 string handlerresult; 30 31 boolean hashandled; 32 33 } 34 //接口 35 public interface iouterhandler { 36 boolean canhandler(context context); 37 38 void handler(context context); 39 }
1 //实现类a 2 public class aouterhandler implements iouterhandler { 3 4 private static string handlename="a"; 5 6 @override 7 public boolean canhandler(context context) { 8 return context.gethandlername()==handlename; 9 } 10 11 @override 12 public void handler(context context) { 13 context.sethandlerresult("没错,就是我处理的:"+this.getclass().getsimplename()); 14 context.sethashandled(true); 15 } 16 } 17 18 //实现类b 19 public class bouterhandler implements iouterhandler { 20 private static string handlename="b"; 21 22 @override 23 public boolean canhandler(context context) { 24 return context.gethandlername()==handlename; 25 } 26 27 @override 28 public void handler(context context) { 29 context.sethandlerresult("没错,就是我处理的:"+this.getclass().getsimplename()); 30 context.sethashandled(true); 31 } 32 } 33 34 //实现类c 35 public class couterhandler implements iouterhandler { 36 private static string handlename="c"; 37 38 @override 39 public boolean canhandler(context context) { 40 return context.gethandlername()==handlename; 41 } 42 43 @override 44 public void handler(context context) { 45 context.sethandlerresult("没错,就是我处理的:"+this.getclass().getsimplename()); 46 context.sethashandled(true); 47 } 48 }
之后我们就需要将这些处理类组装成责任链进行处理,具体代码如下:
1 public class executor { 2 public static void main(string[] args){ 3 arraylist<iouterhandler> handlers=gethandlers(); 4 context context1=new context(); 5 context1.sethandlername("a"); 6 system.out.println(exe(handlers,context1).gethandlerresult()); 7 8 context context2=new context(); 9 context2.sethandlername("c"); 10 system.out.println(exe(handlers,context2).gethandlerresult()); 11 } 12 13 private static arraylist<iouterhandler> gethandlers() { 14 arraylist<iouterhandler> handlers = new arraylist<>(); 15 handlers.add(new aouterhandler()); 16 handlers.add(new bouterhandler()); 17 handlers.add(new couterhandler()); 18 return handlers; 19 } 20 21 private static context exe(arraylist<iouterhandler> handlers,context context){ 22 if(handlers!=null&&handlers.size()!=0){ 23 handlers.foreach(handler->{ 24 if(context.ishashandled()){ 25 return; 26 } 27 if(handler.canhandler(context)){ 28 handler.handler(context); 29 } 30 }); 31 } 32 return context; 33 } 34 }
我们可以看见,exe方法就是实现的主体(这里用了foreach函数,所以没有进行短路处理,实际上如果context.ishashandled==true后,没有必要进行后面的循环),原则就是当前类是否能够处理,如果不能,就交付给下一个处理函数,当然可能是到最后也没有被处理,这种情况可以不处理直接返回,也可能是使用默认处理函数,不过这不重要了。这种处理方式是存在缺陷的,就是俩个handler想联合处理,是做不到的。所以责任链模式,就发展出内置的形式。
内置方式
内置方式还是看代码:
//contenx略,见上文 public interface iinnerhandler { void sethandler(iinnerhandler handler); void hanlder(context context); }
1 //类a 2 public class ainnerhandler implements iinnerhandler { 3 private static string handlename="a"; 4 private iinnerhandler handler; 5 6 @override 7 public void sethandler(iinnerhandler handler) { 8 this.handler=handler; 9 } 10 11 @override 12 public void hanlder(context context) { 13 if(context.gethandlername().equals(handlename)){ 14 context.sethandlerresult("没错,就是我处理的:"+this.getclass().getsimplename()); 15 //不需要这句,因为没有意义了 16 //context.sethashandled(true); 17 }else { 18 handler.hanlder(context); 19 } 20 } 21 22 //类b 23 public class binnerhandler implements iinnerhandler { 24 private static string handlename="a"; 25 private static string handlename2="c"; 26 private iinnerhandler handler; 27 28 @override 29 public void sethandler(iinnerhandler handler) { 30 this.handler=handler; 31 } 32 33 @override 34 public void hanlder(context context) { 35 if(handlename.equals(context.gethandlername())||handlename2.equals(context.gethandlername())){ 36 for (int i=0;i<3;i++){ 37 handler.hanlder(context); 38 } 39 } 40 } 41 } 42 //类c 43 44 public class cinnerhandler implements iinnerhandler { 45 private static string handlename="c"; 46 private iinnerhandler handler; 47 48 @override 49 public void sethandler(iinnerhandler handler) { 50 this.handler=handler; 51 } 52 53 @override 54 public void hanlder(context context) { 55 if(context.gethandlername().equals(handlename)){ 56 string resultinfo="***没错,就是我处理的:"+this.getclass().getsimplename(); 57 if(context.gethandlerresult()==null){ 58 context.sethandlerresult(resultinfo); 59 }else { 60 context.sethandlerresult(context.gethandlerresult() + "\n" + resultinfo); 61 } 62 }else { 63 handler.hanlder(context); 64 } 65 } 66 }
之后我们将内置实现类组合实现责任链处理
1 public class executor { 2 public static void main(string[] args){ 3 iinnerhandler handler=gethandler(); 4 5 context context1=new context(); 6 context1.sethandlername("a"); 7 handler.hanlder(context1); 8 system.out.println(context1.gethandlerresult()); 9 10 context context2=new context(); 11 context2.sethandlername("c"); 12 handler.hanlder(context2); 13 system.out.println(context2.gethandlerresult()); 14 } 15 16 private static iinnerhandler gethandler() { 17 iinnerhandler ahandler=new ainnerhandler(),bhandler=new binnerhandler(),chandler=new cinnerhandler(); 18 bhandler.sethandler(chandler); 19 ahandler.sethandler(bhandler); 20 return ahandler; 21 } 22 }
处理的结果如下:
我们可以看见,内置完全不同于外置,对于a、c类来说,他的作用就是处理,如果处理不了让下一个类处理,这和外置是类似的。但是b类,他可以自己处理,也可以和a,c联合处理。本例中,b就自己未做处理,只是让c处理了三次。所以明显可以看出内置功能更加强大。但是等等,像b,c这种组合,明显是装饰者模式,怎么是责任链呢?
【装饰者模式】
什么是装饰者?还是看代码吧
1 //上下文 2 public class context { 3 private arraylist<string> arraylist=new arraylist<string>(); 4 public arraylist<string> getarraylist(){ 5 return arraylist; 6 } 7 public void add(string moreinfo){ 8 arraylist.add(moreinfo); 9 } 10 } 11 //装饰者接口 12 public interface idecorator { 13 void setdecorator(idecorator decorator); 14 15 void domore(context context); 16 }
1 //adecorator 2 public class adecorator implements idecorator { 3 idecorator decorator; 4 5 public void setdecorator(idecorator decorator) { 6 this.decorator = decorator; 7 } 8 9 public void domore(context context) { 10 context.add(this.getclass().getsimplename()); 11 decorator.domore(context); 12 context.add(this.getclass().getsimplename()); 13 } 14 } 15 16 // bdecorator 17 public class bdecorator implements idecorator { 18 idecorator decorator; 19 20 public void setdecorator(idecorator decorator) { 21 this.decorator = decorator; 22 } 23 24 public void domore(context context) { 25 context.add(this.getclass().getsimplename()); 26 decorator.domore(context); 27 context.add(this.getclass().getsimplename()); 28 } 29 } 30 31 //cdecorator 32 public class cdecorator implements idecorator { 33 idecorator decorator; 34 35 public void setdecorator(idecorator decorator) { 36 this.decorator = decorator; 37 } 38 39 public void domore(context context) { 40 context.add(this.getclass().getsimplename()); 41 //decorator.domore(context); 42 context.add("最后一项需要短路"); 43 context.add(this.getclass().getsimplename()); 44 } 45 }
装饰者装配和执行的代码如下:
1 public class executor { 2 public static void main(string[] args) { 3 idecorator decorator = getdecorator(); 4 context context = new context(); 5 decorator.domore(context); 6 context.getarraylist().foreach(mesage -> system.out.println(mesage)); 7 } 8 9 private static idecorator getdecorator() { 10 idecorator ade = new adecorator(), 11 bad = new bdecorator(), 12 cad = new cdecorator(); 13 bad.setdecorator(cad); 14 ade.setdecorator(bad); 15 return ade; 16 } 17 }
执行的结果:
【对比】
责任链(外置):有一个类负责任,在找到这个负责的类之前,其他的类都是看一样是否和自己有关。而找到这个负责的类后,一般也会短路,不会继续往下执行。所以从责任链重点在于谁负责。
装饰者:在构成的链路中,每一个类都发挥自己的作用,并且不会进行短路,直到最后一个类。
责任链(内置):和装饰者在接口层面,出来名字不同,没有什么不一样的。所以它是用装饰者的身体,装责任链的思想。是一个杂交体。至于是责任链还是装饰者,就看内部实现是否有短路,是否有具体负责任的。很可能是俩个都有。
【思考】
责任链和装饰者这种变形,是否是java中常用的,是否有其他变形的实现呢?答案是有,下节将让你看见不一样的责任链(装饰者)。