前言
生活中有许多事情可以理解成分步骤执行的东西,比如请客吃饭,无论吃什么,一般都包含着点单,吃东西,买单几个步骤,不论吃面还是吃大餐,其他步骤不会变,最多变变点单,在软件开发中,也会有类似的情况出现,我们可以有个点单的基类,然后子类里面具体实现是吃面还是点大餐,这就是模板方法模式,这种模式利用了面向对象的多态性,提高了代码的复用性
什么是模板方法模式 Template Method Pattern
定义一个操作中算法的框架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法结构即可重定义该算法的某些特定步骤,模板方法模式是一种类行为型模式
模板方法模式的优点
(1)、模板方法模式在父类的形式下定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法并不会改变算法中步骤的执行次序
(2)、模板方法模式是一种代码复用技术,它在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类当中,而通过其子类来实现不同的行为,它鼓励恰当的使用继承来实现代码复用
(3)、模板方法模式可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行
(4)、在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同的实现,更换和增加新的子类都很方便,符合单一职责原则和开闭原则
模板方法模式的缺点
模板方法主要的缺点我认为是:需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法不多,将会导致类的个数的增加,系统更加庞大,设计也更加抽象,此时,可以结合桥接模式来进行设计
模板方法模式的使用场景
(1)、对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节交给其子类来实现,即一次性的实现算法的不变部分,并将可变的行为留给子类来实现
(2)、各子类中公共的行为应被提取出来并集中到一个公共父类中来避免代码的重复
(3)、需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制
模板方法模式的具体实现
目录结构
抽象类
package com.company;
//账户类:抽象类
public abstract class Account {
//基本方法---具体方法
public boolean validate(String account,String password){
System.out.println("账号"+account);
if(account.equalsIgnoreCase("张无忌") && password.equalsIgnoreCase("123")){
return true;
}else {
return false;
}
}
//基本方法---抽象方法
public abstract void calculateInterest();
//基本方法----具体方法
public void display(){
System.out.println("显示利息!!");
}
//模板方法
public void handle(String account,String password){
if(!validate(account,password)){
System.out.println("账户或者密码错误");
return;
}
calculateInterest();
display();
}
}
子类实现细节
package com.company;
//活期账户类:具体子类
public class CurrentAccount extends Account {
@Override
//覆盖父类的抽象基本方法
public void calculateInterest() {
System.out.println("按定期利率计算利息");
}
}
辅助类
package com.company;
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 {
public static Object getBean(){
try {
//获取文档对象
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document document=builder.parse(new File(XMLUtil.class.getClassLoader().getResource("").getPath()+"cfg.xml"));
//获取节点信息
NodeList nodeList=document.getElementsByTagName("className");
Node node=nodeList.item(0).getFirstChild();
String className=node.getNodeValue();
//通过类名生成实例并返回
Class c=Class.forName(className);
Object object=c.newInstance();
return object;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}
xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<className>com.company.CurrentAccount</className>
</config>
测试类
package com.company;
public class Main {
public static void main(String[] args) {
Account account;
account=(Account) XMLUtil.getBean();
account.handle("张无忌","123");
}
}
转账请注明出处,掌声送给社会人