概述模板模式是在一个操作中定义一个算法的骨架,然后将一些步骤推迟到子类中。模板方法允许子类在不改变算法结构的情况下重新定义算法的某些步骤。我们都知道泡茶的基本步骤(算法骨架)是:烧水、泡茶、喝茶。整个过程的关键步骤是泡茶。泡茶需要什么样的茶?浸泡多长时间?(留给子类自己实现)。写过API接口的API码农都知道,写一个API一般有四个步骤:参数解析、参数校验、业务处理、返回参数组织。将请求参数解析成业务的请求参数json,解析成实体类;对于参数校验,可以使用通用的方法判断参数是否为空,也可以自己定义一个特殊的校验方法;一般每个处理业务的接口都不一样,基本自己实现;至于返回参数,可能要根据API接口业务返回。支付订单做过支付相关系统的都知道,一个支付订单大致分为三个步骤:组织银行或第三方支付公司的请求参数,发起支付,处理返回结果。以上三个场景中的步骤就是算法的骨架。至于每一步,每个人喝茶的喜好可能不同,API接口服务不同,银行或第三方支付的支付处理也不同。您可能需要自己进行特殊处理。现实实现一个API接口算法类包com.tian.springbootdemo.controller;importcom.tian.springbootdemo.rep.Result;/***@auther:老田*@Description:templateclass*/publicabstractclassAbstractTemplate{/***算法框架*/publicResultexecute(){//第一步:解析参数parseRequestParameters();//第二步:检查参数checkRequestParameters();//第三步:业务处理Objectdata=doBusiness();//第四步:整理返回参数returnassembleResponseParameters(data);}/***解析参数*/publicabstractvoidparseRequestParameters();/***检查参数*/publicabstractvoidcheckRequestParameters();/***业务处理*/publicabstractObjectdoBusiness();/***组织返回参数*/publicabstractResultassembleResponseParameters(Objectobject);}实现类1importcom.tian.springbootdemo.rep.Result;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestMethod;importorg.springframework.web.bind.annotation.ResponseBody;/***@auther:老田*@Description:api接口*/@RequestMapping("/api")@ControllerpublicclassMyApiControllerextendsAbstractTemplate{@RequestMapping(value="/users",method=RequestMethod.POST)@ResponseBody@OverridepublicResultexecute(){returnsuper。执行();}@OverridepublicvoidparseRequestParameters(){System.out.println("*****解析参数*****");}@OverridepublicvoidcheckRequestParameters(){System.out.println("*****检查参数*****");}@OverridepublicObjectdoBusiness(){System.out.println("*****处理业务*****");//TODO:2018/11/17调用服务处理业务Useruser=newUser();user.setName("小天哥");用户.setId(1);user.setAge(20);user.setSex("男人");返回用户;}@OverridepublicResultassembleResponseParameters(Objectobject){System.out.println("*****返回参数*****");结果result=newResult("200","处理成功");结果.setData(对象);返回结果;}}实现类2importcom.tian.springbootdemo.dao.domain.User;importcom.tian.springbootdemo.rep.Result;importorg.springframework.web。bind.annotation.*;/***@auther:老田*@Description:apiinterface*/@RequestMapping("/api")@RestControllerpublicclassLoginControllerextendsAbstractTemplate{@PostMapping(value="/login")@OverridepublicResultexecute(){返回super.execute();}@OverridepublicvoidparseRequestParameters(){System.out.println("解析登录参数");}@OverridepublicvoidcheckRequestParameters(){System.out.println("检查登录用户名是否为空,密码是否为空");}@OverridepublicObjectdoBusiness(){System.out.println("通过用户名查询该用户是否存在");系统输出。println("检查用户密码是否正确");System.out.println("登录成功");用户user=newUser();user.setName("小天哥");用户.setId(1);用户.setAge(20);user.setSex("男人");返回用户;}@OverridepublicResultassembleResponseParameters(Objectobject){System.out.println("*****返回参数*****");结果result=newResult("200","登录成功");结果.setData(对象);返回结果;}}相关类/***@auther:老田*@Description:返回信息*/publicclassResult{//返回码privateStringresponses电子代码;//描述privateStringmessage;//数据privateObjectdata;publicResult(){}publicResult(StringresponseCode,Stringmessage){this.responseCode=responseCode;this.message=消息;}publicResult(StringresponseCode,Stringmessage,Objectdata){this.responseCode=responseCode;this.message=消息;这个。数据=数据;}publicStringgetResponseCode(){返回响应代码;}publicvoidsetResponseCode(StringresponseCode){this.responseCode=responseCode;}publicStringgetMessage(){返回消息;}publicvoidsetMessage(Stringmessage){this.message=message;}publicObjectgetData(){返回数据;}publicvoidsetData(Objectdata){this.data=data;}}importjava.io.Serializable;/***@auther:老田*@Description:数据*/publicclassUserimplementsSerializable{//idprivateIntegerid;//用用户名privateStringname;//性别privateStringsex;//年龄privateintage;publicUser(){}publicUser(Integerid,Stringname,Stringsex,intage){this.id=id;this.name=名称;this.sex=性别;这个。年龄=年龄;}publicIntegergetId(){返回id;}publicvoidsetId(Integerid){this.id=id;}publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}publicStringgetSex(){返回性别;}publicvoidsetSex(Stringsex){this.sex=sex;}publicintgetAge(){返回年龄;}publicvoidsetAge(intage){this.age=age;}}这里使用的思路是在Tools下测试RESTClient进行接口测试:模板设计模式到我们具体的代码中,同样的,我们也可以实现其他的API实现类。另外,参数校验也可以在AbstractTemplate中实现一个默认的方法,例如:校验参数是否为空,但是子类也可以重写这个方法,自己做一个特殊的校验;例如:如果参数中有手机号,那么我们不仅要检查手机号是否为空,还要检查手机号是否为11位数字,是否合法等。优点和模板模式的缺点提高代码的复用性,将相同部分的代码放在抽象类中;提高可扩展性,将不同的放在不同的实现类中,通过扩展实现类来添加一些你需要的行为;实现反向控制,通过父类调用实现类的操作,在实现类的扩展中添加新的行为实现反向控制。缺点是因为引入了抽象类,每一个不同的实现都需要一个子类来实现,这样会导致类的数量增加,从而导致系统实现的复杂性。大佬们在框架中是怎么使用的?Spring中AbstractApplicationContext中的refresh方法是模板方法,源码为:@Overridepublicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this.startupShutdownMonitor){//调用容器准备刷新的方法,并获取容器的当前时间,//同时为容器设置同步标志prepareRefresh();//告诉子类启动refreshBeanFactory()方法//Bean定义资源文件的加载从子类ConfigurableListableBeanFactory的refreshBeanFactory()方法开始beanFactory=obtainFreshBeanFactory();//为BeanFactory配置容器特性,如类加载器、事件处理器等prepareBeanFactory(beanFactory);try{//为容器的某些子类指定特殊的BeanPost事件处理器//-----子类实现postProcessBeanFactory(beanFactory);//调用所有注册的BeanFactoryPostProcessors的BeaninvokeBeanFactoryPostProcessors(beanFactory);//为BeanFactory注册BeanPost事件处理器。//BeanPostProcessor是一个Bean后处理器,//用来监听容器触发的事件registerBeanPostProcessors(beanFactory);//初始化信息源,与国际化相关。初始化消息源();//初始化容器事件传播器。initApplicationEventMulticaster();//调用子类一些特殊的Bean初始化方法//-----子类实现onRefresh();//为事件传播器注册事件监听器。注册监听器();//初始化所有剩余的单例beanfinishBeanFactory初始化(beanFactory);//初始化容器的生命周期事件处理器,//并发布容器的生命周期事件finishRefresh();//.....该方法是上下文启动模板方法这是模板模式在Spring中的应用场景之一。Mybatis中BaseExecutor中的update方法是一个模板方法/***SqlSession.update/insert/delete会调用这个方法*模板方法*/@Overridepublicintupdate(MappedStatementms,Objectparameter)throwsSQLException{ErrorContext.instance().resource(ms.getResource()).activity("执行更新").object(ms.getId());if(closed){thrownewExecutorException("Executorwasclosed.");}//先清除本地缓存,再更新,如何更新由子类决定,//TemplatemethodpatternclearLocalCache();//子类实现(钩子方法)returndoUpdate(ms,parameter);}BaseExecutor中只定义了方法,但是实现在子类中对象参数,RowBoundsrowBounds,ResultHandlerresultHandler,BoundSqlboundSql)throwsSQLException;//...do开头的方法交给具体的子类来实现BaseExecutor的实现类如下:enterimagedescriptionhere实现类SimpleExecutor中doUpdate方法的实现@OverridepublicintdoUpdate(MappedStatementms,对象参数)抛出SQLException{语句stmt=null;try{配置configuration=ms.getConfiguration();//新建StatementHandler//这里我们看到传入的ResultHandler为nullStatementHandlerhandler=configuration.newStatementHandler(this,ms,parameter,RowBounds.DEFAULT,null,null);//准备语句stmt=prepareStatement(handler,ms.getStatementLog());//StatementHandler.updatereturnhandler.update(stmt);}最后{closeStatement(stmt);}}实现类ReuseExecutordoUpdate方法的实现@OverridepublicintdoUpdate(MappedStatementms,Objectparameter)throwsSQLException{Configurationconfiguration=ms.getConfiguration();//同SimpleExecutor,//新建StatementHandler//这里可以看到ResultHandler传入nullStatementHandlerhandler=configuration.newStatementHandler(this,ms,parameter,RowBounds.DEFAULT,null,null);//准备语句Statementstmt=prepareStatement(handler,ms.getStatementLog());返回处理程序更新(stmt);}这是模板方法模式在Mybatis中的经典应用总结模板方法模式定义了一个算法骨架,然后每个实现类实现自己的业务逻辑。在Spring、Mybatis、Dubbo等框架中都有很好的实现案例。相对来说,模板法模式比较简单,面试的时候可以和面试官聊一会。“为了更好的未来,现在受点苦也没什么”
