整体算法的设计是一个抽象类, 它有一系列抽象方法, 代表算法中可被定制的步骤, 同时这个类中包含了一些通用代码。 算法的每一个变种由具体的类实现, 它们重写了抽象方法, 提供了相应的实现。
模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某些细节,有助于算法的扩展。通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
示例:
假设有一个检查流程,要检查身份信息,信用信息,收入情况。这些信息来源不同,如检查公司和个人的信息情况,那么对于不同的来源信息,检查方法不同,但是检查流程是统一的,如定义个流程(或者是优先级) 检查身份信息-->信用信息-->收入情况。
代码实现:
public class TemplateTest{ /** * 检查使用的模板 */ static abstract class CheckTemplate { //检查身份信息 protected abstract void identity(); //检查信用信息 protected abstract void creditHistory(); //检查收入信息 protected abstract void incomeHistory(); //检查流程定义 public void check(){ this.identity(); this.creditHistory(); this.incomeHistory(); } } /** * 检查模式的基类,提供默认的实现 */ static class CheckTemplateBase extends CheckTemplate{ @Override protected void identity() { System.out.println("basecheck identity"); } @Override protected void creditHistory() { System.out.println("basecheck creditHistory"); } @Override protected void incomeHistory() { System.out.println("basecheck incomeHistory"); } } static class CheckCompany extends CheckTemplateBase{ @Override protected void incomeHistory() { System.out.println("check company"); } } //测试 public static void main(String[] args) { CheckCompany checkCompany = new CheckCompany(); checkCompany.check(); } }
说明:
1、定义一个检查模板CheckTemplate ,模板中定义了 protected 的抽象检查方法,主要是不对外提供调用。check() 方法提供是的检查流程。
2、声明检查模板接着声明检查的基类 CheckTemplateBase ,主要为了提供一个默认的实现,所有的检查类可以继承这个基类。
3、最后就是具体的要检查的类型 CheckCompany 继承 CheckTemplateBase 类,可以实现具体的检查方式。
java8 函数jdk8 函数式编程实现,使用“函数接口”
代码:
public class TemplateTest{ /** * 函数接口 */ interface Criteria{ void check(); } /** * 模板 */ static class CheckTemplate { //函数接口 作为属性 private final Criteria identity; private final Criteria creditHistory; private final Criteria incomeHistory; public CheckTemplate(Criteria identity, Criteria creditHistory, Criteria incomeHistory) { this.identity = identity; this.creditHistory = creditHistory; this.incomeHistory = incomeHistory; } //模板方法 public void checkLoanApplication(){ identity.check(); creditHistory.check(); incomeHistory.check(); } } /** * 默认的检查类,每一个方法,都对应一个 函数接口 * 所有的处理子类实现可以继承此类 */ static class CheckBase { public void identity() { System.out.println("basecheck identity"); } public void creditHistory() { System.out.println("basecheck creditHistory"); } public void incomeHistory() { System.out.println("basecheck incomeHistory"); } } /** * 检查 */ static class Check extends CheckTemplate { public Check(CheckBase check) { //传入都是函数接口 super(check::identity, check::creditHistory, check::incomeHistory); } } /** * Company 处理流程 * */ static class CompanyCheck extends CheckBase { //重写 creditHistory 方法 public void creditHistory(){ System.out.println("company creditHistory "); } } public static void main(String[] args) { Check c = new Check(new CompanyCheck()); c.checkLoanApplication(); } }说明:
1、首先声明一个函数式接口 Criteria,定义了一个检查方法 check()
2、声明检查模板 CheckTemplate,在模板是声明了Criteria 属性,用来作为检查流程的定义,每一个Criteria 属性对应一个检查流程的一个环节。
3、检查的基类 CheckBase 主要为了提供一个默认的实现,所有的检查类可以继承这个基类。
4、声明具体检查 CompanyCheck extends CheckBase,可以自定义检查的内容,如果不定义就使用默认的。
5、声明检查类 Check extends CheckTemplate ,声明了一个构造方法参数是检查基类(接口也可以) CheckBase。有两个作用:a:用于所有的具休检查类的基类,b:Check 构造方法的参数,只要是CheckBase 子类就可以构造Check ,代码清晰规范。在构造方法中,直接调用父类的构造方法,参数就是“函数接口”。
java8终极代码:
public class TemplateTest{ /** * 函数接口 */ interface Criteria{ void check(); } /** * 模板 */ static class CheckTemplate { //函数接口 作为属性 private final Criteria identity; private final Criteria creditHistory; private final Criteria incomeHistory; public CheckTemplate(Criteria identity, Criteria creditHistory, Criteria incomeHistory) { this.identity = identity; this.creditHistory = creditHistory; this.incomeHistory = incomeHistory; } //模板方法 public void checkLoanApplication(){ identity.check(); creditHistory.check(); incomeHistory.check(); } } /** * 默认的检查类,每一个方法,都对应一个 函数接口 * 所有的处理子类实现可以继承此类 */ static class CheckBase { public void companyIdentity() { System.out.println("company identity"); } public void companyCreditHistory() { System.out.println("company creditHistory"); } public void companyIncomeHistory() { System.out.println("company incomeHistory"); } //大公司的收入检查 public void bigCompanyIncomeHistory() { System.out.println("big company incomeHistory"); } } public static void main(String[] args) { CheckBase checkBase = new CheckBase(); CheckTemplate checkTemplate = new CheckTemplate(checkBase::companyIdentity,checkBase::companyCreditHistory,checkBase::bigCompanyIncomeHistory); checkTemplate.checkLoanApplication(); } }
两种实现方式比较:
第一种实现要每一个要检查的对象都要被创建一个具体的类,而java8的实现可以直接传入“函数接口”。
在示例中声明了一个具体的类,也可以把所有查检方式(具体方法)都声明在CheckBase 类中,根据不同的检查对象直接传入“函数”就可以,这样就避免为每一个检查对象创建一个类。