23.模板方法模式

1.什么是模板方法模式?

定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

举个例子:吃饭 = 点单+吃东西+买单。 点单和买单大同小异,吃什么可能大不相同。将点单买单的实现放在父类,吃东西在父类中做个声明,实现放在子类。

 

2.模板方法模式结构

(1)AbstractClass(抽象类):在抽象类中定义一系列基本操作,每个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法,用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。

(2)ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。

 

3.模板方法模式实现

(1)模板方法

模板方法是一个具体方法,它给出了一个顶层逻辑框架,而逻辑的组成步骤在抽象类中可以是具体方法,也可以是抽象方法。不能是接口。

(2)基本方法

基本方法是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又分为3种:抽象方法,具体方法,钩子方法。

/**
 * 模板方法1
 */
public class Template {
    public void templateMethod(){
        open();
        display();
        //通过钩子方法来确定某一步骤是否执行
        if(isPrint()){
            print();
        }
    }

    //钩子方法
    public boolean isPrint(){
        return true;
    }
}
/**
 * 模板方法2:抽象类
 */
public abstract class AbstractClass {
    //模板方法
    public void templateMethod(){
        operation1();
        operation2();
        operation3();
    }

    //基本方法——具体方法
    protected void operation1(){
        //实现代码
    }

    //基本方法——抽象方法
    protected abstract void operation2();

    //基本方法——钩子方法
    protected void operation3(){

    }

    
}
public class ConcreteClass extends AbstractClass {
    @Override
    protected void operation2() {
        //实现代码
    }

    protected void operation3() {
        //实现代码
    }
}

 

4.模板方法实例——不同账户类型显示不同利息计算公式

(1)账户类,充当抽象类

/**
 * 账户类,充当抽象类
 */
public abstract class Account {
    //基本方法——具体方法
    public boolean validate(String account,String password){
        System.out.println("账户:"+account);
        System.out.println("密码:"+password);
        if(account.equalsIgnoreCase("张无忌")&&password.equalsIgnoreCase("123456")){
            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();
    }
}

(2)活期账户类:具体子类

/**
 * 活期账户类:具体子类
 */
public class CurrentAccount extends Account {
    //覆盖父类的抽象基本方法
    @Override
    public void calculateInterest() {
        System.out.println("按活期利率计算利息");
    }
}

(3)定期账户类,充当具体子类

/**
 * 定期账户类,充当具体子类
 */
public class SavingAccount extends Account {
    //覆盖父类的抽象基本方法
    @Override
    public void calculateInterest() {
        System.out.println("按定期利率计算利息");
    }
}

(4)配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<config>
    <className>controller.templateModuleRate.CurrentAccount</className>
</config>

(5)工具类

public class XMLUtil {
    /**
     * 从xml配置文件中提取具体类的类名,并返回一个实例对象
     */
    public static Object getBean(){
        try {
            //创建DOM文档对象
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
            Document document = builder.parse(new File("src//controller//templateModuleRate//config.xml"));

            //获取包含类名的文本节点
            NodeList nl = document.getElementsByTagName("className");
            Node classNode = nl.item(0).getFirstChild();
            String cName = classNode.getNodeValue();

            //通过类名生成实例对象并将其返回
            Class c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;

        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }

    }
}

(6)客户端

public class Client {
    public static void main(String[] args) {
        Account account;
        account = (Account) XMLUtil.getBean();
        account.handle("张无忌","123456");
    }
}

(7)路径及结果

 

5.钩子方法的使用实例——获取数据,转换为XML格式,显示数据

(1)抽象方法

/**
 * 抽象方法
 */
public abstract class DataViewer {
    //抽象方法:获取数据
    public abstract void getData();

    //具体方法:转换数据
    public void convertData(){
        System.out.println("将数据转换为xml格式");
    }

    //抽象方法:显示数据
    public abstract void displayData();

    //钩子方法:判断是否为xml格式数据
    public boolean isNotXMLData(){
        return true;
    }

    //模板方法
    public void process(){
        getData();
        //如果不是xml格式的数据,则进行数据转换
        if(isNotXMLData()){
            convertData();
        }
        displayData();
    }
}

(2)具体方法

/**
 * 具体方法
 */
public class XmlDataViewer extends DataViewer {
    @Override
    public void getData() {
        System.out.println("从xml文件中获取数据");
    }

    @Override
    public void displayData() {
        System.out.println("以柱形图显示数据");
    }

    //覆盖父类钩子方法
    public boolean isNotXMLData(){
        return false;
    }
}

(3)客户端

public class Client {
    public static void main(String[] args) {
        DataViewer dataViewer = new XmlDataViewer();
        dataViewer.process();
    }
}

(4)路径及结果

 

6.模板方法优缺点

优:

(1)父类中形式化定义一个算法,子类处理细节

(2)模板方法是一种代码复用技术

(3)可实现反向控制

(4)通过子类覆盖父类方法,可以提供不同实现

 

缺:

    类数量可能过多

 

7.适用环境

(1)分割复杂算法

(2)各子类公共行为提取出来

(3)通过子类决定父类哪个步骤是否执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹏哥哥啊Aaaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值