模板方法模式简述
模板方法(Template Method)模式的定义如下:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。可以理解为:每个人做的一系列事件的顺序固定,不同的人做同一件事的方式不一样,它是一种类行为型模式。
模板方法模式结构
模板方法模式结构如下:
(1) 抽象模板类(AbstractTemplate):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。
① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
② 基本方法:是整个算法中的一个步骤,包含以下几种类型。
- 抽象方法(abstractMethod1,abstractMethod2):在抽象类中申明,由具体子类实现。
- 具体方法(specificMethod):在抽象类中已经实现,在具体子类中可以继承或重写它。
- 钩子方法(hook,booleanHook):在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种(由子类改变模板方法的一些逻辑)。
(2) 具体子类(ConcreteTemplate1 ,ConcreteTemplate2 ):实现抽象类中所定义的抽象方法和钩子方法,当然具体方法也是可以重写的,它们是一个顶级逻辑的一个组成步骤。
模板方法模式代码实现
/** * 抽象模板角色 */ public abstract class AbstractTemplate { // 模板方法 public void templateMethod(){ abstractMethod01(); abstractMethod02(); if(booleanHook()){ specificMethod(); } hook(); } /*抽象方法1*/ protected abstract void abstractMethod01(); /*抽象方法2*/ protected abstract void abstractMethod02(); /*具体方法*/ protected void specificMethod() { System.out.println("没有重写的specificMethod方法"); } /*空实现的钩子函数*/ protected void hook(){}; /*判断用的钩子函数,默认返回false*/ protected boolean booleanHook(){return false;} } /** * 具体模板角色,模板方法不需要重写,重写抽象方法,具体方法,钩子方法。判断用的钩子方法返回true; */ public class ConcreteTemplate extends AbstractTemplate { @Override protected void specificMethod() { System.out.println("重写 specificMethod方法"); } @Override protected void hook() { System.out.println("重写hook方法"); } @Override protected boolean booleanHook() { return true; } @Override protected void abstractMethod01() { System.out.println("重写 abstractMethod01方法"); } @Override protected void abstractMethod02() { System.out.println("重写 abstractMethod02方法"); } } /** * 具体模板角色,判断钩子方法返回ture,具体方法不重写。抽象方法,钩子方法重写,模板方法不重写 */ public class ConcreteTemplate1 extends AbstractTemplate { @Override protected void hook() { System.out.println("重写hook方法"); } @Override protected boolean booleanHook() { return true; } @Override protected void abstractMethod01() { System.out.println("重写 abstractMethod01方法"); } @Override protected void abstractMethod02() { System.out.println("重写 abstractMethod02方法"); } } ** * 模式方法客户端类 * 优点: 1、封装不变部分,扩展可变部分。 * 2、提取公共代码,便于维护。 * 3、行为由父类控制,子类实现。 * 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。 */ public class TemplateClient { public static void main(String[] args) { //创建具体模板类,抽象类具体方法重写 AbstractTemplate template=new ConcreteTemplate(); //调用模板方法也叫钩子函数 template.templateMethod(); //创建具体模板类,抽象类具体方法不重写 AbstractTemplate template1=new ConcreteTemplate1(); //调用模板方法也叫钩子函数 template1.templateMethod(); } }
模板方法模式案例
现在模式普通人做土豆丝跟厨师做土豆丝的流程为例,uml图如下:
具体代码如下:
/** * 抽象模板类,做土豆丝类 */ public abstract class CookingPotato { /**炒土豆丝的顺序*/ public void cook(){ oil(); potato(); salt(); if(vinegarFlag()){ vinegar(); } } /*是否放醋*/ protected boolean vinegarFlag() { return false; } /*放醋*/ protected void vinegar(){ System.out.println("放入适当的醋"); }; /*放盐*/ protected abstract void salt(); /*放土地丝*/ private void potato() { System.out.println("放入足量的土豆丝"); } /*放油*/ protected abstract void oil(); } /** * 厨师做土豆丝 */ public class Cooker extends CookingPotato{ @Override protected boolean vinegarFlag() { return true; } @Override protected void salt() { System.out.println("放入适量的盐"); } @Override protected void oil() { System.out.println("放入适量的油"); } } /** * 普通人做土豆丝 */ public class CommonPeople extends CookingPotato { @Override protected boolean vinegarFlag() { return false; } @Override protected void salt() { System.out.println("盐放多了。。。"); } @Override protected void oil() { System.out.println("油放多了。。。"); } } /** * 客户端 */ public class ClientTest { public static void main(String[] args) { CookingPotato cooker=new Cooker(); CookingPotato commonPeople=new CommonPeople(); //厨师的cook方法 cooker.cook(); System.out.println("-------------------------------"); //普通人的cook方法 commonPeople.cook(); } }
运行结果如下:
模板方法模式优点与缺点
优点如下:
- 封装不变部分,扩展可变部分。不变部分算法由父类实现,可变部分的算法由子类实现,便于子类扩展。
- 在父类提取了公共的代码,提供代码的复用性。
- 遵循了开闭原则,通过子类继承父来方式进行功能的扩展与增强。
缺点如下:
- 每一种实现都要创建一个子类,导致系统的类过多。
- 子类的某个行为动作ji影响父类某个行为动作,这是一种子父类反向结果,影响了代码的可读性。