模板方法 (宝,我输液了,输的想你的夜)

沙海 2021年6月16日04:25:55Java评论49字数 5291阅读17分38秒阅读模式
摘要

模板方法 (宝,我输液了,输的想你的夜) 原创 三太子敖丙 三太子敖丙

模板方法 (宝,我输液了,输的想你的夜)

原创 三太子敖丙 三太子敖丙 文章源自JAVA秀-https://www.javaxiu.com/32937.html

收录于话题文章源自JAVA秀-https://www.javaxiu.com/32937.html

#设计模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

9个文章源自JAVA秀-https://www.javaxiu.com/32937.html

大家每到一家公司都会发现,每个公司都会有一个规范,比如说请假流程规范,代码规范等等。每个公司都有这个流程,只是里面的具体执行条件不一样而已。文章源自JAVA秀-https://www.javaxiu.com/32937.html

在设计模式中的模版方法模式,也是可以理解为一种规范模版。主要是提升我们代码的复用性,以及扩展等问题。文章源自JAVA秀-https://www.javaxiu.com/32937.html

这样的模板方法在我们当舔狗跟妹妹们聊天的时候也是可以用到的,比如这样一个模板:文章源自JAVA秀-https://www.javaxiu.com/32937.html

“宝,XXXX了,XXXX什么XX?X你的XXX”文章源自JAVA秀-https://www.javaxiu.com/32937.html

当我拿到这样一个模板的时候,我就可以举一反三直接套用了,我们直接填参数就可以了,比如:文章源自JAVA秀-https://www.javaxiu.com/32937.html

“宝,我打疫苗了,打的什么苗 ,爱你的每一秒 ”文章源自JAVA秀-https://www.javaxiu.com/32937.html

“宝,我做核酸了,做的什么酸,得不到你的心酸”文章源自JAVA秀-https://www.javaxiu.com/32937.html

“宝,今天去输液了,输的什么液,想你的夜”文章源自JAVA秀-https://www.javaxiu.com/32937.html

...........文章源自JAVA秀-https://www.javaxiu.com/32937.html

好了言归正传,在框架中模版方法模式也是很常见的。文章源自JAVA秀-https://www.javaxiu.com/32937.html

今天就具体来聊聊设计模式中行为型设计模式中模版方法模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

设计模式系列往期文章:文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 单例模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 工厂模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 流程引擎文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 建造者模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 原型模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 责任链模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 观察者模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 策略模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

大纲

模板方法 (宝,我输液了,输的想你的夜)文章源自JAVA秀-https://www.javaxiu.com/32937.html

还是老规矩从上图五个方面来分别具体和大家聊聊模版方法模式文章源自JAVA秀-https://www.javaxiu.com/32937.html

定义

模版方法模式的定义以及目的?文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 定义:模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • 目的:1.使用模版方法模式的目的是避免编写重复代码,以便开发人员可以专注于核心业务逻辑的实现文章源自JAVA秀-https://www.javaxiu.com/32937.html

    2.解决接口与接口实现类之间继承矛盾问题文章源自JAVA秀-https://www.javaxiu.com/32937.html

    以上定义来自《设计模式之美》文章源自JAVA秀-https://www.javaxiu.com/32937.html

结构图:文章源自JAVA秀-https://www.javaxiu.com/32937.html

模板方法 (宝,我输液了,输的想你的夜)文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • AbstractTemplate(抽象模版):定义一系列抽象方法,或者实现的方法,又或者是钩子方法。即:定义流程文章源自JAVA秀-https://www.javaxiu.com/32937.html

  • ConcreteTemplate(具体模版):实现父类抽象方法,基于本身不同的模版业务逻辑,实现不同的业务逻辑代码。即:抽象方法实现相同,内部逻辑不同文章源自JAVA秀-https://www.javaxiu.com/32937.html

整个结构图看起来还是很简单的,但是还是要理解设计模式解决什么问题。文章源自JAVA秀-https://www.javaxiu.com/32937.html

代码实现?还是举例吧。文章源自JAVA秀-https://www.javaxiu.com/32937.html

还是以上面的请假举例吧,假设现在A公司请假需要直属领导审批以及通知HR有人请假了就可以了,B公司需要直属领导,部门负责人审批最后通知HR,方能完成整个请假流程。那作为OA办公流程怎么去处理这个问题嘛?直接看代码实现吧!文章源自JAVA秀-https://www.javaxiu.com/32937.html

public abstract class AskForLeaveFlow {    // 一级组长直接审批    protected abstract void firstGroupLeader(String name);    // 二级组长部门负责人审批    protected void secondGroupLeader(String name) {    }    // 告知HR有人请假了    private final void notifyHr(String name) {        System.out.println("当前有人请假了,请假人:" + name);    }    // 请假流模版    public void askForLeave(String name) {        firstGroupLeader(name);        secondGroupLeader(name);        notifyHr(name);    }}

首先还是定义一个请假流程,其中:文章源自JAVA秀-https://www.javaxiu.com/32937.html

firstGroupLeader方法为abstract修饰,则作为子类都是必须要实现的文章源自JAVA秀-https://www.javaxiu.com/32937.html

secondGroupLeader 二级领导审批,在子类中可以重写,也可不重写文章源自JAVA秀-https://www.javaxiu.com/32937.html

notifyHr 方法为通知HR,已经内部实现文章源自JAVA秀-https://www.javaxiu.com/32937.html

最后一个askForLeave请假流程方法,把以上模版方法串起来文章源自JAVA秀-https://www.javaxiu.com/32937.html

public class CompanyA extends AskForLeaveFlow {        @Override    protected void firstGroupLeader(String name) {        System.out.println("CompanyA 组内有人请假,请假人:" + name);    }}public class CompanyB extends AskForLeaveFlow {    @Override    protected void firstGroupLeader(String name) {        System.out.println("CompanyB 组内有人请假,请假人:" + name);    }    @Override    protected void secondGroupLeader(String name){        System.out.println("CompanyB 部门有人请假,请假人:" + name);    }}

在CompanyA以及CompanyB中,secondGroupLeader二级领导可以选择重写或者不重写,这个类模版方法简称为钩子方法。文章源自JAVA秀-https://www.javaxiu.com/32937.html

public class testTemplate {    public static void main(String[] args) {        // 公司A请假流程模版        AskForLeaveFlow companyA = new CompanyA();        companyA.askForLeave("敖丙");        // 结果:CompanyA 组内有人请假,请假人:敖丙        //       当前有人请假了,请假人:敖丙        AskForLeaveFlow companyB = new CompanyB();        companyB.askForLeave("敖丙");        // 结果:CompanyB 组内有人请假,请假人:敖丙        //      CompanyB 部门有人请假,请假人:敖丙        //      当前有人请假了,请假人:敖丙    }}

最后就是看测试dome结果了。companyA和companyB分别输出了对应的请假流程。文章源自JAVA秀-https://www.javaxiu.com/32937.html

细心的同学可能已经发现了,做为模版方法中里面除了可以有抽象方法外,还可以有具体的实现方法以及钩子方法。文章源自JAVA秀-https://www.javaxiu.com/32937.html

所以大家在应用的过程可以多考虑考虑在内部定义模版方法时,应该定义成抽象方法还是其它的。文章源自JAVA秀-https://www.javaxiu.com/32937.html

框架中的应用

模版方法模式在我们常见的Java的框架中也是非常常见的,只是可能我们平时没有注意到这一点而已。文章源自JAVA秀-https://www.javaxiu.com/32937.html

第一个:首先我们学SpringMVC的时候,最开始都会写一些Servlet来作为处理一些post或者get请求等。文章源自JAVA秀-https://www.javaxiu.com/32937.html

模板方法 (宝,我输液了,输的想你的夜)文章源自JAVA秀-https://www.javaxiu.com/32937.html

这里直接看这个源码大家就可以发现这也是直接使用模版方法模式的思想,期间在HttpServlet 继承GenericServlet中也还是模版方法的体现,这说明了可以多次抽象构建模版。文章源自JAVA秀-https://www.javaxiu.com/32937.html

第二个:常见问的文件流中,Java IO 类中的InputStream、OutputStream、Reader、Writer等都能看到模版方法模式的身影。文章源自JAVA秀-https://www.javaxiu.com/32937.html

模板方法 (宝,我输液了,输的想你的夜)文章源自JAVA秀-https://www.javaxiu.com/32937.html

上面是我贴出的部分InputStream的源码,主要看这个read模版方法,也就是模版方法模式的体现。文章源自JAVA秀-https://www.javaxiu.com/32937.html

当然IO类中还有很多其他的,我就不一一贴源码出来了,感情兴趣的同学,可以自己打开源码了解了解。文章源自JAVA秀-https://www.javaxiu.com/32937.html

业务举例

在业务中怎么使用模版方法?文章源自JAVA秀-https://www.javaxiu.com/32937.html

首先需要理解模版方法它是为了增加代码的复用性,以及扩展性而存在的,所以本着这个思想我还是给大家举一个例子吧。文章源自JAVA秀-https://www.javaxiu.com/32937.html

之前写责任链模式最后给大家举例商品详情,这次还是用商品详情,但是用模版方法模式来实现这个问题,理解为商详2.0版本。文章源自JAVA秀-https://www.javaxiu.com/32937.html

商品详情展示我们可以是分模块展示的,比如头图,商品信息,sku信息,配送地址,分期付费等等。文章源自JAVA秀-https://www.javaxiu.com/32937.html

那么怎么进行组装到商品详情的展示呢?文章源自JAVA秀-https://www.javaxiu.com/32937.html

流程图:文章源自JAVA秀-https://www.javaxiu.com/32937.html

模板方法 (宝,我输液了,输的想你的夜)文章源自JAVA秀-https://www.javaxiu.com/32937.html

可以看到一个请求过来,可以有模块组装器选择组装返回结果。文章源自JAVA秀-https://www.javaxiu.com/32937.html

提一个点,在第二步请求的模块的时候为了减少整个链路的请求时间可以考虑是串行,或者并行(开线程池处理)。文章源自JAVA秀-https://www.javaxiu.com/32937.html

接下来直接看代码吧文章源自JAVA秀-https://www.javaxiu.com/32937.html

public abstract class AbstractTemplateBlock<T> {    // 组装结果    public T template(ModelContainer modelContainer) {        T block = initBlock();        try {            this.doWork(modelContainer, block);        } catch (Exception e) {            // 可以选择捕获异常,是中断流程,还是只打印日志,不中断流程        }        return block;    }    // 初始化构建返回结果模型    protected abstract T initBlock();    // 定义抽象模版    protected abstract void doWork(ModelContainer modelContainer, T block) throws Exception;}

还是先创建模版Block文章源自JAVA秀-https://www.javaxiu.com/32937.html

@Componentpublic class ItemInfoBlock extends AbstractTemplateBlock<ItemInfoBlock.ItemInfo> {    @Override    protected ItemInfoBlock.ItemInfo initBlock() {        return new ItemInfoBlock.ItemInfo();    }    // 模拟业务逻辑,组装返回商品信息模块数据    @Override    protected void doWork(ModelContainer modelContainer, ItemInfo block) throws Exception {        block.setItemId(123L);        block.setItemName("测试");    }    @Data    public static class ItemInfo {        private Long itemId;        private String itemName;    }}

这里只写了一个ItemInfoBlock,其他的模块也是这一样的写法,所以就不全写出来了。文章源自JAVA秀-https://www.javaxiu.com/32937.html

    public static void main(String[] args) {        // 1.模拟获取SpringBean        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");        ItemInfoBlock itemInfoBlock = (ItemInfoBlock) applicationContext.getBean("itemInfoBlock");      // 2. ModelContainer可以理解为贯穿上下文中的请求参数,或者一些组装数据需要的预加载数据       ModelContainer modelContainer  = new ModelContainer();       // 3. 获取返回结果       ItemInfoBlock.ItemInfo itemInfo = itemInfoBlock.template(modelContainer);       System.out.println(JSON.toJSONString(itemInfo));       // 结果:{"itemId":123,"itemName":"测试"}    }

最后就是看测试demo了,可以看到再每一个模块中都是有一个AbstractTemplateBlock,内部包含doWork抽象方法,由子类去实现当前自己的业务逻辑。文章源自JAVA秀-https://www.javaxiu.com/32937.html

同时第三步获取返回结果时,我只是单独列出来,大家可以根据实际情况还能做改造。比如说返回map结构等 mapKey 是模块名称,value是数据。文章源自JAVA秀-https://www.javaxiu.com/32937.html

当前这种组装商品详情的模式也是比较常见的一种方式。代码的复用性高,同时扩展性也有一定的体现,符合模版方法模式的思想。文章源自JAVA秀-https://www.javaxiu.com/32937.html

总结

模版方法模式的特点大家应该也能体会到了,适用场景还是为了增加代码的复用性,以及扩展性。文章源自JAVA秀-https://www.javaxiu.com/32937.html

还是那句话存在即合理,不要因设计模式而在写代码时强行嵌套。合理的学习每种设计模式适合场景,解决什么问题。文章源自JAVA秀-https://www.javaxiu.com/32937.html

宝,明天我可能无法正常更新了,我生病了在输液。文章源自JAVA秀-https://www.javaxiu.com/32937.html

模板方法 (宝,我输液了,输的想你的夜)文章源自JAVA秀-https://www.javaxiu.com/32937.html

继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定