定义 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(定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤) 优点 封装不变部分,扩展可变部分 提取公共部分代码,便于维护 行为由父类控制,子类实现 缺点 按照一般设计习惯,抽象类负责声明最抽象、最一般的事务属性和方法,实现类完成具体的事务属性和方法。但是模板方法模式却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,在复杂的项目中,会带来代码阅读的难度 使用场景 场景:多个子类有公有的方法,并且逻辑基本相同时。 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现 重构时使用,把相同的代码抽取到父类中,然后通过钩子函数约束其行为(参考模板方法模式的扩展)。 模板方法模式在开源框架中运用广泛,提供一个抽象类,然后提供了一堆子类。如果需要扩展功能,可以继承这个抽象类,然后复写protected方法,然后在调用一个类是execute方法,就能完成扩展开发。 代码 模板方法模式可能是最常用的设计模式之一了,因为它只需要依靠Java或者其他语言的扩展机制就能实现。并且由于它太基本了,可能使你并没有意识到自己使用的是模板方法模式
通用类图
基本的模板方法模式 类图
代码 模板父类(抽象类 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.pattern.templatemethod.template;public abstract class AbstractClass { protected abstract void step1 () ; protected abstract void step2 () ; protected abstract void step3 () ; public final void start () { this .step1(); this .step2(); this .step3(); } }
具体子类1(继承自模板父类 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.pattern.templatemethod.template;public class ConcreteClass1 extends AbstractClass { @Override protected void step1 () { System.out.println("ConcreteClass1步骤1" ); } @Override protected void step2 () { System.out.println("ConcreteClass1步骤2" ); } @Override protected void step3 () { System.out.println("ConcreteClass1步骤3" ); } }
具体子类2(继承自模板父类 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.pattern.templatemethod.template;public class ConcreteClass2 extends AbstractClass { @Override protected void step1 () { System.out.println("ConcreteClass2步骤1" ); } @Override protected void step2 () { System.out.println("ConcreteClass2步骤2" ); } @Override protected void step3 () { System.out.println("ConcreteClass2步骤3" ); } }
测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.pattern;import com.pattern.templatemethod.template.AbstractClass;import com.pattern.templatemethod.template.ConcreteClass1;import com.pattern.templatemethod.template.ConcreteClass2;import org.junit.Test;public class TemplateMethodTest { @Test public void TemplateTest () { AbstractClass client1 = new ConcreteClass1 (); AbstractClass client2 = new ConcreteClass2 (); client1.start(); client2.start(); } }
结果
模板方法模式的扩展 类图
代码 模板父类(抽象类 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.pattern.templatemethod.extend;public abstract class AbstractExtendClass { protected abstract void step1 () ; protected abstract void step2 () ; protected abstract void step3 () ; protected abstract void step4 () ; protected boolean isExecute () { return true ; } public final void start () { this .step1(); this .step2(); this .step3(); if (isExecute()){ this .step4(); } } }
具体子类1(继承自模板父类 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.pattern.templatemethod.extend;public class ConcreteExtendClass1 extends AbstractExtendClass { @Override protected void step1 () { System.out.println("ConcreteClass1步骤1" ); } @Override protected void step2 () { System.out.println("ConcreteClass1步骤2" ); } @Override protected void step3 () { System.out.println("ConcreteClass1步骤3" ); } @Override protected void step4 () { System.out.println("钩子被激活,执行了步骤4" ); } @Override protected boolean isExecute () { return false ; } }
具体子类2(继承自模板父类 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.pattern.templatemethod.extend;public class ConcreteExtendClass2 extends AbstractExtendClass { private boolean execute; @Override protected void step1 () { System.out.println("ConcreteClass2步骤1" ); } @Override protected void step2 () { System.out.println("ConcreteClass2步骤2" ); } @Override protected void step3 () { System.out.println("ConcreteClass2步骤3" ); } @Override protected void step4 () { System.out.println("钩子被激活,执行了步骤4" ); } @Override protected boolean isExecute () { return this .execute; } public void setExecute (boolean execute) { this .execute = execute; } }
测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.pattern;import com.pattern.templatemethod.extend.AbstractExtendClass;import com.pattern.templatemethod.extend.ConcreteExtendClass1;import com.pattern.templatemethod.extend.ConcreteExtendClass2;import com.pattern.templatemethod.template.AbstractClass;import com.pattern.templatemethod.template.ConcreteClass1;import com.pattern.templatemethod.template.ConcreteClass2;import org.junit.Test;public class TemplateMethodTest { @Test public void ExtendTemplateTest () { ConcreteExtendClass1 client1 = new ConcreteExtendClass1 (); ConcreteExtendClass2 client2 = new ConcreteExtendClass2 (); System.out.println("----------子类1并不需要执行步骤4-----------" ); client1.start(); System.out.println("----------首先子类2想执行步骤4-----------" ); client2.setExecute(true ); client2.start(); System.out.println("----------然后子类2不想执行步骤4了-----------" ); client2.setExecute(false ); client2.start(); } }
运行结果
注意 为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写 抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问权限。