模板方法模式

简介: 开发软件时一个常见的情况是有一个通用的算法,只是步骤上略有不同。我们希望不同的 实现能够遵守通用模式,保证它们使用了同一个算法,也是为了让代码更加易读。一旦你 从整体上理解了算法,就能更容易理解其各种实现。

开发软件时一个常见的情况是有一个通用的算法,只是步骤上略有不同。我们希望不同的 实现能够遵守通用模式,保证它们使用了同一个算法,也是为了让代码更加易读。一旦你 从整体上理解了算法,就能更容易理解其各种实现。

 模板方法模式是为这些情况设计的:整体算法的设计是一个抽象类,它有一系列抽象方法,代表算法中可被定制的步骤,同时这个类中包含了一些通用代码。算法的每一个变种 由具体的类实现,它们重写了抽象方法,提供了相应的实现。 

让我们假想一个情境来搞明白这是怎么回事。假设我们是一家银行,需要对公众、公司和 职员放贷。放贷程序大体一致即验明身份、信用记录和收入记录。这些信息来源不一, 衡量标准也不一样。你可以查看一个家庭的账单来核对个人身份;公司都在官方机构注册 过,比如美国的SEC、英国的Companies House。 

我们先使用一个抽象类LoanApplication 来控制算法结构,该类包含一些贷款调查结果 报告的通用代码。根据不同的申请人,有不同的类:CompanyLoanApplication、Personal LoanApplication 和EmployeeLoanApplication。图1 展示了LoanApplication 类的结构。


img_f31932f27aae7db6b13dd8ce6fe244a9.png
图1 使用模板方法模式描述申请贷款过程


CompanyLoanApplication 的checkIdentity 方法在Companies House 等注册公司数据库中查找相关信息。checkIncomeHistory 方法评估公司的现有利润、损益表和资产负债表。checkCreditHistory 方法则查看现有的坏账和未偿债务。

PersonalLoanApplication 的checkIdentity 方法通过分析客户提供的纸本结算单,确认客户地址是否真实有效。checkIncomeHistory 方法通过检查工资条判断客户是否仍被雇佣。checkCreditHistory 方法则会将工作交给外部的信用卡支付提供商。

EmployeeLoanApplication 就是没有查阅员工历史功能的PersonalLoanApplication。为了方便起见,我们的银行在雇佣员工时会查阅所有员工的收入记录图 2。

img_5568e4ee952b35380e2213212c753337.png
图2 员工申请贷款是个人申请的一种特殊情况


使用Lambda 表达式和方法引用,我们能换个角度思考模板方法模式,实现方式也跟以前不一样。模板方法模式真正要做的是将一组方法调用按一定顺序组织起来。如果用函数接口表示函数,用Lambda 表达式或者方法引用实现这些接口,相比使用继承构建算法,就会得到极大的灵活性。让我们看看如何使用这种方式实现LoanApplication 算法,请看图3


img_49b6d3feba3157d545c771482530f5c1.png
图3 员工申请贷款的例子


正如读者所见, 这里没有使用一系列的抽象方法, 而是多出一些属性:identity、creditHistory 和incomeHistory。每一个属性都实现了函数接口Criteria,该接口检查一项标准,如果不达标就抛出一个问题域里的异常。我们也可以选择从check 方法返回一个类来表示成功或失败,但是沿用异常更加符合先前的实现图4。


img_ab8a8a794e8f5050c41d6659fc88b157.png
图4  如果申请失败,函数接口Criteria 抛出异常


采用这种方式,而不是基于继承的模式的好处是不需要在LoanApplication 及其子类中实现算法,分配功能时有了更大的灵活性。比如,我们想让Company 类负责所有的检查,那么Company 类就会多出一系列方法,如图5。


img_a2ed0da5c79ead033859dcf9a2f002c5.png
图5 Company 类中的检查方法


现在只需为CompanyLoanApplication 类传入对应的方法引用,如图6。


img_3ff433b7218cf6610971139f01924984.png
图6 CompanyLoanApplication 类声明了对应的检查方法


将行为分配给Company 类的原因是各个国家之间确认公司信息的方式不同。在英国,Companies House 规范了注册公司信息的地址,但在美国,各个州的政策是不一样的。

使用函数接口实现检查方法并没有排除继承的方式。我们可以显式地在这些类中使用Lambda 表达式或者方法引用。

我们也不需要强制EmployeeLoanApplication 继承PersonalLoanApplication 来达到复用,可以对同一个方法传递引用。它们之间是否天然存在继承关系取决于员工的借贷是否是普通人借贷这种特殊情况,或者是另外一种不同类型的借贷。因此,使用这种方式能让我们更加紧密地为问题建模。

目录
相关文章
|
2月前
|
设计模式 算法 Java
Java设计模式——模板方法模式
Java设计模式——模板方法模式
41 2
|
9月前
|
设计模式 XML 算法
模板方法模式
模板方法模式是一种行为型设计模式,它定义了一种算法的框架,将算法的具体实现留给子类来完成。模板方法模式在实现算法时,使用了一种称为“钩子方法”的技巧,通过在模板方法中添加一些抽象方法或虚方法,来让子类自行实现具体的算法细节,从而实现了算法的复用和扩展。
65 3
|
10月前
|
算法 前端开发
关于模板方法模式我所知道的
关于模板方法模式我所知道的
62 0
|
11月前
|
算法 Java 程序员
行为型模式-模板方法模式
行为型模式-模板方法模式
77 0
|
设计模式 算法 Java
Java设计模式 ->模板方法模式
Java设计模式 ->模板方法模式
74 0
|
设计模式
我学会了,模板方法模式
模板方法模式属于行为型模式,这个类型的设计模式总结出了 类、对象之间的经典交互方式,将类、对象的行为和使用解耦了,花式的去使用对象的行为来完成特定场景下的功能。
58 0
我学会了,模板方法模式
|
SQL 设计模式 Java
|
设计模式 缓存 算法
浅析Java设计模式【3.6】——模板方法
Java常用设计模式,模板模式
102 0
浅析Java设计模式【3.6】——模板方法
|
设计模式 算法 Java
Java设计模式-模板方法模式
Java设计模式-模板方法模式
136 0
Java设计模式-模板方法模式
|
设计模式 算法 Java
【玩转23种Java设计模式】行为型模式篇:策略模式
策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。