模板方式模式可以说是设计模式中比较简单的一类,简单的说其实现过程是多态的扩展,为什么这么说呢?下面具体介绍一下模板方法模式的概念及实际生产使用情况。(理解不到位请见谅啊!)
模板方法模式简单的说就是抽象父类定义抽象方法及运作流程,子类继承以实现具体工作。举个简单的例子: 男生洗头和女生洗头之间的差别,(以不洗澡,只洗头为例)首先对洗头这件事情主要有一下几个流程: 准备---->挤洗发液---->清洗---->吹干(比较邋遢,洗一次就行了)。
public abstract class WashHair { //准备阶段 protected abstract void prepare(); //挤洗发液 protected abstract void extrudedShampoo(); //清洗 protected abstract void wash(); //吹干 protected abstract void dry(); //流程 public void templateMethod() { prepare(); extrudedShampoo(); wash(); dry(); } }
那么到男生开始洗头了,流程如下: 脱衣服(光膀子)----> 拧起沐浴露---->一顿抓----->风干。
public class ManWashHair extends WashHair { @Override protected void prepare() { // TODO Auto-generated method stub System.out.println("光着膀子"); } @Override protected void extrudedShampoo() { // TODO Auto-generated method stub System.out.println("拧起沐浴露"); } @Override protected void wash() { // TODO Auto-generated method stub System.out.println("一顿狂抓"); } @Override protected void dry() { // TODO Auto-generated method stub System.out.println("自然风干"); } }
男生洗头比较粗糙,不讲究。现在女生开始洗头,当然肯定不能脱光膀子是吧,准备(不能耍流氓,过程不说了)---->选择洗发液---->按摩清洗(其实估计也没这么讲究)---->吹风机。
public class WamanWashHair extends WashHair{ @Override protected void prepare() { // TODO Auto-generated method stub System.out.println("准备"); } @Override protected void extrudedShampoo() { // TODO Auto-generated method stub System.out.println("选择洗发液,护发素"); } @Override protected void wash() { // TODO Auto-generated method stub System.out.println("按摩清洗"); } @Override protected void dry() { // TODO Auto-generated method stub System.out.println("吹风机吹干"); } }
好,现在基本代码都写完了,我们先说好处再来测试。优点: 解耦,首先我们不在直接操作男生或者女生这个对象,而是操作我们的抽象类。其次方便扩展,这一点很重要,比如在公司里面有一个流程很多业务都需要使用,但是每一个业务都自己编写相同的一套流程太low了,而且新的业务增加时还需要再写一遍重复的流程,如果使用模板方法模式,就可以直接扩展,在调用的时候直接调用就行。缺点:增加了代码的可阅读性,为什么这么说?简单的解释,这样子类的实现过程直接影响父类的执行结果。
测试一下:
public class WashMain { public static void main(String[] args) { //将子类向上转型为父抽象类 WashHair manWashHair = new ManWashHair(); WashHair womanWashHair = new WomanWashHair(); //男女生分别执行洗头 manWashHair.templateMethod(); womanWashHair.templateMethod(); } }
现在模板方法工厂学习完成,那么在实际生产中会不会这么搞呢?其实也可以,但是不灵活,给大家介绍原来一个项目的解决方案,使用xml来解决。在上面的例子中我们发现我们建立的模板是方法层面上面的,就是说直接调用的是方法,但是在实际生产中则侧重于类层面的(不知道这么说是不是符合专业用语啊!),同时也有方法侧面,下面给大家介绍一个建房的例子(自己想的,如果业务逻辑不对的话就将就看吧)。
建房需要这么几个步骤,买地---->准建审批---->招募工程队---->修建,这样一个详细的过程,其中涉及到公司修建和个人修建(小城市)。下面简单介绍一下两者不同的实现过程,
首先公司买地需要开会,造价计算,而个人则是衡量自身的经济水平,准备资金。
准建审批,公司需要提供公司资历,提交修建保证金,个人则需要提交保证金,请领导吃饭。
招募工程队,公司需要招标,投标公司资历审核,决标成交,个人则需要打听哪个包工头技术好,商讨价格即可。
下面是详细的实现过程。
针对买地,审批,招募,修建的代码不做展示,将代码的目录结构放出来。
具体看看build的过程,通过Build入口方法build来执行,通过spring setter方法注入buyLand,audit,conscribe的不同实现类(分为company和person)。
package com.module.entry; import com.module.audit.Audit; import com.module.buyland.BuyLand; import com.module.conscribe.Conscribe; /** * * Project Name:Model * ClassName:Build * Description: * @author: libo * @date: 2018年11月10日 下午4:54:42 * note:主要完成修建的过程,在类的层面上实现模板方法模式 * */ public class Build { //通过spring注入 private BuyLand buyLand; private Audit audited; private Conscribe conscribe; //具体修建过程 public void build() { buyLand.excute(); audited.excute(); conscribe.excute(); } public BuyLand getBuyLand() { return buyLand; } public void setBuyLand(BuyLand buyLand) { this.buyLand = buyLand; } public Audit getAudited() { return audited; } public void setAudited(Audit audit) { this.audited = audit; } public Conscribe getConscribe() { return conscribe; } public void setConscribe(Conscribe conscribe) { this.conscribe = conscribe; } }
下面是spring的配置文件,通过spring的配置文件可以轻松的决定整个修建过程的注入类,这样方便修改和扩展。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 采用xml注入的方式分别注入buyLand,Audit,conscribe的实现类 也可以配置自动扫描来进行注解注入 两种方式都可以--> <bean id="companyBuyLand" class="com.module.buyland.CompanyBuyLand"></bean> <bean id="personBuyLand" class="com.module.buyland.PersonBuyLand"></bean> <bean id="companyAudited" class="com.module.audit.CompanyAudited"></bean> <bean id="personAudited" class="com.module.audit.PersonAudited"></bean> <bean id="companyConscribe" class="com.module.conscribe.CompanyConscribe"></bean> <bean id="personConscribe" class="com.module.conscribe.PersonConscribe"></bean> <!--通过注入不同的实现类来完成不同的工作--> <bean id="personBuild" class="com.module.entry.Build"> <property name="buyLand" ref="personBuyLand"></property> <property name="audited" ref="personAudited"></property> <property name="conscribe" ref="personConscribe"></property> </bean> <bean id="companyBuild" class="com.module.entry.Build"> <property name="buyLand" ref="companyBuyLand"></property> <property name="audited" ref="companyAudited"></property> <property name="conscribe" ref="companyConscribe"></property> </bean> </beans>
下面是main函数及运行结果:
在原来的项目中,一个架构师使用这种方式完成订单框架的基本结构,并且完成通过spring进行流程内业务的配置,觉得很牛逼,如果我在这写的不清楚或者有错误,望见谅!如果你有更好的理解,也请留言告诉我,谢谢!