模板方法模式:剖析模板方法在JDK、Tomcat、Mybatis等开源框架中的应用 迈不过友情╰ 2022-08-30 04:15 51阅读 0赞 > 首发CSDN:[徐同学呀][Link 1],原创不易,转载请注明源链接。我是徐同学,用心输出高质量文章,希望对你有所帮助。 ### 文章目录 ### * * 一、模板方法定义 * 二、通用写法 * 三、模板方法在源码架构中的体现 * * 1、JDK中模板方法的体现 * 2、Tomcat中生命周期设计用到了模板方法 * 3、Mybatis中模板方法的体现 * 四、要点回顾 ## 一、模板方法定义 ## 模板方法模式,原理非常简单,在GOF的祖师爷设计模式一书中定义如下: > Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure. 大概的意思就是:在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。 > 这里的“算法”,可以理解为广义上的“业务逻辑”,算法骨架就是“模板”,包含算法骨架的方法就是“模板方法”,这也是模板方法模式名字的由来。(摘自《设计模式之美》王争) 从定义可以体会到模板方法模式主要有两个特点: * **代码复用**:所有的子类可以复用父类模板方法的代码。 * **功能扩展**:父类留给子类重写的步骤方法就是一个个扩展点,可以在不修改框架源码的情况下,子类基于扩展点定制化框架的功能。 ## 二、通用写法 ## 说实在的,模板方法就是把公共部分,放到抽象父类里让所有子类共享,再留一些扩展方法让子类自行实现,其类图如下: ![template method][] public interface Template { void templateMethod(); } public abstract class AbstractTemplate implements Template { @Override public void templateMethod() { System.out.println("templateMethod...start"); step1(); step2(); step3(); System.out.println("templateMethod...end"); } protected abstract void step1(); protected abstract void step2(); protected abstract void step3(); } public class TemplateA extends AbstractTemplate { @Override protected void step1() { System.out.println("TemplateA...step1"); } @Override protected void step2() { System.out.println("TemplateA...step2"); } @Override protected void step3() { System.out.println("TemplateA...step3"); } } public class TemplateB extends AbstractTemplate { @Override protected void step1() { System.out.println("TemplateB...step1"); } @Override protected void step2() { System.out.println("TemplateB...step2"); } @Override protected void step3() { System.out.println("TemplateB...step3"); } } public class Test { public static void main(String[] args) { Template templateA = new TemplateA(); templateA.templateMethod(); System.out.println("------------------------------"); Template templateB = new TemplateB(); templateB.templateMethod(); } } // 控制台输出 templateMethod...start TemplateA...step1 TemplateA...step2 TemplateA...step3 templateMethod...end ------------------------------ templateMethod...start TemplateB...step1 TemplateB...step2 TemplateB...step3 templateMethod...end 注意: 抽象父类`AbstractTemplate`中,`step1()`、`step2()`、`step3()`都是抽象方法,子类必须实现,这也算是模板方法模式的一个缺点吧,但是可以通过提供空方法实现避免子类必须重写这些方法,也可以在空方法体内抛异常,达到不强制实现,但是使用时必须实现的效果。 ## 三、模板方法在源码架构中的体现 ## ### 1、JDK中模板方法的体现 ### JDK中用到模板方法的地方实在太多了: (1)JUC中AQS本身是提供了一套同步控制器的模板,可以通过这一套模板,实现`ReentrantLock`、`ReentrantReadWriteLock`、`CountDownLatch`、`Semaphore`等。 独占锁的获取释放、共享锁的获取释放,`AbstractQueuedSynchronizer`都使用了模板方法。拿独占模式获取锁举例,`acquire`是独占模式获取锁的模板方法,将同步队列的操作放在父类,在进入同步队列前的`tryAcquire`留给子类实现: public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { public final void acquire(int arg) { //若没有抢到锁,则进入等待队列 if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //自己中断自己 selfInterrupt(); } protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); } } (2)io模块中有很多用到模板方法的地方,拿`InputStream`举例,提供了一个`read(byte b[], int off, int len)`模板方法,同时又留了一个抽象的`read()`让子类实现: public abstract class InputStream implements Closeable { public abstract int read() throws IOException; public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } // 子类需要实现read int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; } } (3)集合中也大量用到模板方法,`AbstractList`、`AbstractCollection`等都是很多集合类的父类,所以会把一些公共部分放在抽象父类中,一些可扩展的方法让子类实现。拿`AbstractList`举例,`AbstractList`本身也是`AbstractCollection`的子类: public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { public boolean add(E e) { add(size(), e); return true; } public void add(int index, E element) { throw new UnsupportedOperationException(); } ... ... } ### 2、Tomcat中生命周期设计用到了模板方法 ### Tomcat中比较明显用到模板方法的是生命周期的设计,所有需要统一生命周期管理的类都可以继承`LifecycleBase`,`LifecycleBase`实现了接口`Lifecycle`。`LifecycleBase` 实现了`init`、`start`、`stop`、`destroy` 等生命周期的方法,也是模板方法,做一些生命周期状态的流转和生命周期监听事件的触发,也留了一些抽象方法 `initInternal`、`startInternal`、`stopInternal`、`destoryInternal`给子类具体实现。Tomcat的一键启动、停止等都得益于其生命周期的设计。 ### 3、Mybatis中模板方法的体现 ### `Mybatis`是一个`ORM`框架,也大量用到模板方法,拿`org.apache.ibatis.executor.BaseExecutor`举例: public abstract class BaseExecutor implements Executor { @Override public int update(MappedStatement ms, Object parameter) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } clearLocalCache(); return doUpdate(ms, parameter); } protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException; protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException; protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException; protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException; } ## 四、要点回顾 ## 模板方法模式,非常之简单,也很容易理解,记住两点:**代码复用**和**功能扩展**。至于扩展点不想强制让子类实现,可以提供默认空实现,或者抛个异常,只有使用时才提醒子类去实现。 参考: * 《设计模式之美》王争 * Mybatis3源码 * JDK源码 * Tomcat10源码 *如若文章有错误理解,欢迎批评指正,同时非常期待你的留言和点赞。如果觉得有用,不妨点个在看,让更多人受益。* [Link 1]: https://stefan.blog.csdn.net/ [template method]: /images/20220829/3ed333b1908c407a85ef40b900389ed6.png
相关 模板方法模式 模板方法模式会将模板方法以及不需要随业务场景变化的基本方法放到父类中实现,随业务场景变化的基本方法会被定义为抽象方法,由子类提供真正的实现。 下图展示了模板方法模式的核心类, 野性酷女/ 2022年09月10日 11:24/ 0 赞/ 37 阅读
相关 模板方法模式:剖析模板方法在JDK、Tomcat、Mybatis等开源框架中的应用 > 首发CSDN:[徐同学呀][Link 1],原创不易,转载请注明源链接。我是徐同学,用心输出高质量文章,希望对你有所帮助。 文章目录 一、模板方法定义 迈不过友情╰/ 2022年08月30日 04:15/ 0 赞/ 52 阅读
相关 模板方法模式-用模板方法排序 package I\_Template.b; import java.util.Arrays; /\\ \ 用模板方法排序 \/ public class Ma Myth丶恋晨/ 2022年07月12日 12:20/ 0 赞/ 152 阅读
相关 模板方法模式 一、描述 模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的 素颜马尾好姑娘i/ 2022年06月03日 01:08/ 0 赞/ 39 阅读
相关 模板方法模式 引入一个例子 ![在这里插入图片描述][70] 比如冲咖啡和冲茶两个过程,加工方法似乎都差不多。可以看成如下过程: 把水煮沸boil()->冲泡brew()->倒 约定不等于承诺〃/ 2022年05月06日 10:38/ 0 赞/ 96 阅读
相关 模板方法模式 最近看书又遇到模板方法模式,具体是在同步器(AQS)的内容上。就顺便再来回顾下。 同步器AbstractQueuedSynchronizer(AQS)是一个抽象类。其中定义了 墨蓝/ 2021年10月18日 11:34/ 0 赞/ 344 阅读
相关 模板方法模式 生活中有很多按步骤才能完成的事,比如我们想进房间,需要先将门打来,然后才能进去,进去之后再把门关上。开门和关门是固定的步骤,而进入房间的步骤则不是固定的,它可以有多种方式,走着 约定不等于承诺〃/ 2021年10月15日 06:45/ 0 赞/ 383 阅读
相关 模板方法模式 什么叫做模板方法模式? 在定义功能时,功能的一部分是确定的但是有一部分是不确定的,而确定的部分在使用不确定的部分。那么这时就将不确定的部分暴露出来,由该类的子类去实现。 清疚/ 2021年09月18日 15:40/ 0 赞/ 418 阅读
相关 模板方法模式 一 点睛 在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些 深藏阁楼爱情的钟/ 2021年07月24日 20:53/ 0 赞/ 467 阅读
相关 模板方法模式 在定义功能时,功能的一部分是确定的,一部分是不确定的,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去,由该类的子类去完成。 抽象类(AbstractCl... 系统管理员/ 2021年05月03日 16:24/ 0 赞/ 445 阅读
还没有评论,来说两句吧...