Java设计模式-模板方法模式
定义
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.定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改
变一个算法的结构即可重定义该算法的某些特定步骤。创新互联服务项目包括东明网站建设、东明网站制作、东明网页制作以及东明网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,东明网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到东明省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
模板方法模式非常简单,主要是用了Java的继承机制,话不多说,直接上代码
实现
抽象模板类
public abstract class AbstractClass { /** * 基本方法 */ protected abstract void doSomething(); /** * 基本方法,可以有默认实现 */ protected void doAnything() { System.out.println("AbstractClass doAnything()"); } /** * 模板方法,为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写 */ public final void templateMethod(){ doSomething(); doAnything(); } }
具体模板类
public class ConcreteClassA extends AbstractClass { @Override protected void doSomething() { System.out.println("ConcreteClassA doSomething()"); } @Override protected void doAnything() { System.out.println("ConcreteClassA doAnything()->我不想使用父类的默认实现,我要覆盖它"); } }
public class ConcreteClassB extends AbstractClass { @Override protected void doSomething() { System.out.println("ConcreteClassB doSomething()"); } // 使用父类doAnything()的默认实现}
客户端代码
public class Client { public static void main(String[] args) { AbstractClass a = new ConcreteClassA(); a.templateMethod(); AbstractClass b = new ConcreteClassB(); b.templateMethod(); } }
优点
- 封装不变部分,扩展可变部分
- 提取公共部分代码,便于维护
- 行为由父类控制,子类实现
缺点
-
子类影响父类
按照我们的设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类完成
具体的事物属性和方法。但是模板方法模式却颠倒了,抽象类定义了部分抽象方法,由子类
实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目
中,会带来代码阅读的难度,而且也会让新手产生不适感。
- 模板方法使用继承方式复用代码,如果要在基本算法里面增加一个步骤,而该步骤是抽象的话,每个子类都要修改代码,实现这个步骤。
使用场景
- 多个子类有公有的方法,并且逻辑基本相同时。
- 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个
子类实现。
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通
过 钩子 函数(详见后面的扩展示例)约束其行为。
扩展
模板方法模式的扩展,主要就是增加了钩子方法(Hook Method),那么什么是“钩子方法”呢?
在抽象模板类中,可以定义一个方法,并允许子类视情况覆盖它来改变基本方法的执行过程(比如决定某些步骤是否需要执行)
钩子方法的作用
- 让子类实现算法中的可选部分,算法中的某些步骤是可选的,子类可以做出决定是否需要这些步骤
- 如果钩子对于子类的实现不重要时,子类可以对钩子置之不理
下面是增加钩子方法后的模板方法模式通用代码:
抽象模板类
public abstract class AbstractClass { /** * 基本方法 */ protected abstract void doSomething(); /** * 基本方法 */ protected void doAnything() { System.out.println("AbstractClass doAnything()"); } /** * 依赖于钩子方法的基本方法 */ protected abstract void dependOnHook(); /** * 模板方法,为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写 */ public final void templateMethod(){ doSomething(); doAnything(); if (hook()){ dependOnHook(); } } /** * 钩子方法:空实现或默认实现,子类可以覆写;由子类的一个方法返回值决定公共部分的执行结果 * @return */ protected boolean hook(){ System.out.println("AbstractClass hook()"); return true; } }
具体模板类
public class ConcreteClassA extends AbstractClass { @Override protected void doSomething() { System.out.println("ConcreteClassA doSomething()"); } @Override protected void doAnything() { System.out.println("ConcreteClassA doAnything()->我不想使用父类的默认实现,我要覆盖它"); } @Override protected void dependOnHook() { System.out.println("ConcreteClassA dependOnHook()"); } // 没有覆写钩子方法,使用默认实现,dependOnHook()将会被调用}
public class ConcreteClassB extends AbstractClass { @Override protected void doSomething() { System.out.println("ConcreteClassB doSomething()"); } // 使用父类doAnything()的默认实现 @Override protected void dependOnHook() { System.out.println("ConcreteClassB dependOnHook()"); } /** * 覆写钩子方法,改变默认实现,改变公共部分(模板方法)的行为,dependOnHook()不会被调用 * @return */ @Override protected boolean hook(){ System.out.println("ConcreteClassB hook()"); return false; } }
源码地址: https://gitee.com/tianranll/java-design-patterns.git
参考文献《设计模式之禅》
文章标题:Java设计模式-模板方法模式
URL分享:http://scyanting.com/article/ghehsd.html