本文转载自微信公众号《Java极客技术》,作者鸭血范。转载本文请联系Java极客技术公众号。1、引入模板模式,顾名思义,定义一个模板,以具体方法或具体构造函数的形式实现部分逻辑,并在抽象类中声明一些抽象方法,强制子类实现剩余逻辑。不同的子类可以用不同的方式实现这些抽象方法,从而对剩下的逻辑有不同的实现,这就是模板方法模式的用武之地。模板模式涉及三个角色:抽象类(AbstractClass):实现了模板方法,定义了算法的骨架;具体类(ConcreteClass):实现抽象类中的抽象方法,完成完整的算法;customer角色:customerclass提出使用特定类的请求;2.例子例如,以早上起床和上班所需的操作为例。大致流程可以分为以下几个步骤:穿衣、刷牙、洗脸、吃早餐等,男生和女生的操作可能会有一些差异。我们创建一个抽象类,定义大致的操作流程,如下://刷牙washFace();//洗脸eatBreakFast();//吃早餐}/**着装*/protectedabstractvoiddressing();/**刷牙*/protectedvoidbrushTeeth(){System.out.println("刷牙");}/**洗脸*/protectedvoidwashFace(){System.out.println("洗脸");}/**吃早餐*/protectedabstractvoideatBreakFast();}因为男孩女孩行为不同,我们创建两个具体的类,如下:System.out.println("直接在公司吃早餐");}}/***girls*具体实现类*/publicclassWomanPersonextendsAbstractPerson{@Overrideprotectedvoiddressing(){System.out.println("穿休闲装");}@OverrideprotectedvoideatBreakFast(){System.out.println("在家买点吃的,或者在外面买点零食");}}创建客户端,实现如下:publicclassTemplateClient{publicstaticvoidmain(String[]args){//男生起步ManPersonmanPerson=newManPerson();System.out.println("-----男生起步-----");manPerson.prepareGoWorking();System.out.println("-----女生起步----");//WomanPersonwomanPerson=newWomanPerson();womanPerson.prepareGoWorking();}}输出结果:-----男孩步---穿西装,刷牙洗脸,吃早餐在公司————女生起床步骤——穿休闲装,刷牙洗脸,在家弄点吃的,或者在外面买点零食当然,模板模式不是唯一的方式来玩,也可以在模板模式下使用钩子什么是钩子?有一个实现为空的方法,我们称这个方法为钩子。子类可以视情况决定是否覆盖它。或者以上面为例。例如,早餐后,您必须去上班。你应该选择什么样的交通工具?抽象类新增方法hook(),内容如下:/***抽象类*/publicabstractclassAbstractPerson{/***定义运行过程*/publicvoidprepareGoWorking(){dressing();//dressingbrushTeeth();//刷牙washFace();//洗脸eatBreakFast();//吃早餐hook();//hook}/**dressing*/protectedabstractvoiddressing();/**刷牙*/protectedvoidbrushTeeth(){System.out.println("刷牙");}/**洗脸*/protectedvoidwashFace(){System.out.println("洗脸");}/**吃早餐*/protectedabstractvoideatBreakFast();/**hook*/protectedvoidhook(){};}Boy具体实现类,重写hook()方法,内容如下:/***Boy*具体实现类*/publicclassManPersonextendsAbstractPerson{@Overrideprotectedvoiddressing(){System.out.println("穿西装");}@OverrideprotectedvoideatBreakFast(){System.out.println("直接在公司吃早餐");}@Overrideprotectedvoidhook(){System.out.println("吃早餐thesubwaytowork");}}运行测试类,男孩的具体实现类,输出结果:-----男孩起步----穿西装,刷牙,洗脸,在公司吃早餐,坐地铁上班当然也有其他的玩法,比如女生洗完脸,可能要化妆。我们再对抽象类进行处理,内容如下:/***抽象类*/publicabstractclassAbstractPerson{/***定义操作流程*/publicvoidprepareGoWorking(){dressing();//穿衣服brushTeeth();//刷牙washFace();//是否需要洗脸,默认不化妆if(isMakeUp()){System.out.println("makeup");}eatBreakFast();//吃早餐hook();//hook}/**是否需要化妆方法*/protectedbooleanisMakeUp(){returnfalse;}/**穿衣服*/protectedabstractvoiddressing();/**刷牙*/protectedvoidbrushTeeth(){系统。out.println("刷牙");}/**洗脸*/protectedvoidwashFace(){System.out.println("洗脸");}/**吃早餐*/protectedabstractvoideatBreakFast();/**hook*/protectedvoidhook(){};}女性具体实现类,重写isMakeUp()方法,内容如下:/***girls*具体实现类*/publicclassWomanPersonextendsAbstractPerson{@Overrideprotectedvoiddressing(){System.out.println("穿休闲服");}@OverrideprotectedvoideatBreakFast(){System.out.println("在家吃点东西,或者在外面买点零食");}@OverrideprotectedbooleanisMakeUp(){returntrue;}}运行测试类,女生执行类,输出Result:-----女生起床步骤----穿便服,刷牙,洗脸,化妆,在家买点吃的,或者在外面买点零食3.应用模板设计模式,应用广泛,比如javaEE中的servlet,我们每次创建servlet都会继承HttpServlet。实际上,HttpServlet已经为我们提供了一套运行程序。我们只需要重写里面的方法即可!HttpServlet部分源码如下:publicabstractclassHttpServletextendsGenericServlet{protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{//...}protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{//...}protectedvoiddoHead(HttpServletRequestreq,HttponservetException){//...protectedvoiddoPut(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{//...}protectedvoiddoDelete(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{//...}protectedvoiddoOptions(HttpServletRequestreq{//...HttpServletRequestreq、HttpServletResponseresp)throwsServletException、IOException{//...}protectedvoidservice(HttpServletRequestreq、HttpServletResponseresp)throwsServletException、IOException{Stringmethod=req.getMethod();if(method.equals(METHOD_GET)){longlastModified=getLastModified(req);if(lastModified==-1){//servlet不支持if-modified-since,noreason//togothroughfurtherexpensivelogicdoGet(req,resp);}else{longifModifiedSince=req.getDateHeader(HEADER_IFMODSINCE);if(ifModifiedSince
