模板方法模式 -常用
定义:一个操作中的算法框架,而将一些步骤延迟到子类中,模板方法模式使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤
1.代码案例
某软件公司要为某银行的业务支撑系统开发一个利息计算模块,利息计算流程如下: 1.系统根据账号和密码验证用户信息,如果用户信息错误,系统显示出错提示。
-
如果用户信息正确,则根据用户类型的不同,使用不同的利息计算公式计算利息(如活期账户和定期账户具有不同的利息计算公式)。
-
系统显示利息
试使用模板方法模式设计该利息计算模块
Account 账户类,充当抽象类
package com.company.Demo;
public abstract class Account {
private boolean validate(String account,String password){
System.out.println("账号:"+account);
System.out.println("密码:"+password);
if ("张三".equalsIgnoreCase(account)&&"1qaz".equalsIgnoreCase(password)){
return true;
}else {
return false;
}
}
protected abstract void calculateInterest();
protected void display(){
System.out.println("显示利息");
}
protected void handle(String account,String password){
if (!validate(account,password)){
System.out.println("用户名或者密码错误");
}else {
calculateInterest();
display();
}
}
}
CurrentAccount 活期账户类,充当具体子类
package com.company.Demo;
public class CurrentAccount extends Account{
@Override
protected void calculateInterest() {
System.out.println("活期账户计算利息!");
}
}
SavingAccount 定期账户类,充当具体子类
package com.company.Demo;
public class SavingAccount extends Account{
@Override
protected void calculateInterest() {
System.out.println("定期账户计算利息!");
}
}
配置文件config.xml 在配置文件中存储了具体命令类的类名
<?xml version="1.0" encoding="ISO-8859-1"?>
<config>
<className>com.company.Demo.CurrentAccount</className>
</config>
XMLUtil工具类,解析config.xml文件获得具体类的对象
package com.company.Demo;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class XMLUtil {
//使用此方法 用于从xml 配置文件中提取具体类的类名,并且返回一个对象
public static Object getBean(){
// 创建 DOM 文档对象
DocumentBuilderFactory builderFactory=DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document parse = builder.parse(new File("D:\\javaProject\\MoreThread\\src\\config.xml"));
// 获取包名的文本节点
NodeList nodeList = parse.getElementsByTagName("className");
Node node = nodeList.item(0).getFirstChild();
//通过类名反射实例化对象,并且返回
String nodeName = node.getNodeValue();
Class<?> clazz = Class.forName(nodeName);
return clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
测试:
package com.company.Demo;
public class Main {
public static void main(String[] args) {
Account bean = (Account)XMLUtil.getBean();
bean.handle("张三","1qaz");
}
}
结果;
账号:张三 密码:1qaz 定期账户计算利息! 显示利息
2.钩子方法
Account 父类
package com.company.Demo;
public abstract class Account {
protected void display(){
System.out.println("使用钩子方法");
}
// 父类钩子方法
protected boolean isHook(){
return true;
}
protected void print(){
if (isHook()){
display();
}else {
System.out.println("子类修改了钩子");
}
}
}
CurrentAccount 子类
package com.company.Demo;
public class CurrentAccount extends Account{
// 子类修改了父类的钩子方法
@Override
protected boolean isHook() {
return false;
}
}
测试:
package com.company.Demo;
public class Main {
public static void main(String[] args) {
Account account=new CurrentAccount();
account.print();
}
}
结果:子类修改了钩子
3.模板方法的优点
1.在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详的处理算法时并不会改变算法中步骤的执行次序
2.模板方法模式是一种代码复用技术,在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类实现不同的行为,它鼓励用户怡当地使用继承来实现代码复用。
3.模板方法模式可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。
4.在模板方法模式中,可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。
4.模板方法的缺点
在模板方法模式中,需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将导致类的个数增加,系统更加庞大,设计也更加抽象,此时可结合桥接模式进行设计
5.模板方法的适用情况
1.对一些复杂的算法进行分割,将其算法中固定不变的部分,设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。即一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
2.各子类中公共的行为应被提取出来,并集中到一个公共父类中以避免代码重复
3.需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制