设计模式之模板方法模式

概述

在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。
例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。
这样的例子在生活中还有很多,例如,一个人每天会起床、吃饭、做事、睡觉等,其中“做事”的内容每天可能不同。我们把这些规定了流程或格式的实例定义成模板,允许使用者根据自己的需求去更新它,例如,简历模板、论文模板、Word 中模板文件等。

定义

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

举个栗子

一个武侠要战斗的时候,也有一套固定的通用模式,那就是运行内功,开启经脉,准备武器和使用招式,我们把这些用代码表示

public abstract class AbstractSwordsman {
    //该方法为final,防止算法框架被覆写
    public void finghting(){
        //运行内功,抽象方法
        neigong();
        //调整经脉,具体方法
        jingmai();
        //如果有武器,则准备武器
        if (hasWeapons()){//2
            weapons();
        }
        //使用招式
        moves();
        //钩子方法
        hook();//1
    }

    //空实现方法
    protected void hook(){}
    protected abstract void neigong();
    protected abstract void weapons();
    protected abstract void moves();
    protected void jingmai() {
        System.out.println("开启经脉");
    }
    /*是否有武器的方法*/
    protected boolean hasWeapons(){
        return true;
    }
}

这个抽象类包含了三种类型的方法,分别是抽象方法,具体方法和钩子方法。(钩子方法:由抽象类声明并且实现,子类也可以选择加以扩展。通常抽象类会给出一个空的钩子方法,也就是没有实现的扩展。它和具体方法在代码上没有区别,不过是一种意识的区别;而它和抽象方法有时候也是没有区别的,就是在子类都需要将其实现的时候。而不同的是抽象方法必须实现,而钩子方法可以选择性实现或者不实现。也就是说钩子方法为你在实现某一个抽象类的时候提供了可选项,相当于预先提供了一个默认配置。)在上面的例子中就是武侠开启经脉的方式都一样,所以就在具体的方法中实现。钩子方法则分为两类:第一类在上面代码的注释1处,它有一个空实现的方法,子类可以视情况来决定是否要覆盖它;第二类在注释2处,这类钩子方法的返回类型通常是boolean类型的,其一般用于对某个条件进行判断,如果条件满足则执行某一步操作,否则将不执行。

具体实现类

武侠以张无忌和张三丰来举例子

public class ZhangWuJi extends AbstractSwordsman {
    private static final String TGA = "张无忌";
    @Override
    protected void neigong() {
        System.out.println(TGA+"运行九阳神功");
    }

    @Override
    protected void weapons() {
    }

    @Override
    protected void moves() {
        System.out.println(TGA+"使用招式乾坤大挪移");
    }

    @Override
    protected boolean hasWeapons() {
        return false;
    }
}

public class ZhangSanFeng extends AbstractSwordsman {
    private static final String TGA = "张三丰";
    @Override
    protected void neigong() {
        System.out.println(TGA+"运行纯阳无极功");
    }

    @Override
    protected void weapons() {
        System.out.println(TGA+"使用太极剑");
    }

    @Override
    protected void moves() {
        System.out.println(TGA+"使用招式太极拳");
    }

    @Override
    protected boolean hasWeapons() {
        return true;
    }

    @Override
    protected void hook() {
        System.out.println(TGA+"突然肚子不舒服,老夫先去趟厕所");
    }
}

张无忌没有武器,所以hasWeapons为false这样也不会进入weapons方法了,张三丰突然感觉肚子不舒服,所以就实现了钩子方法hook,用来处理一些自定义的逻辑。

客户端调用

public class Client {
    public static void main(String[] args) {
        ZhangWuJi zhangWuJi = new ZhangWuJi();
        zhangWuJi.finghting();
        ZhangSanFeng zhangSanFeng = new ZhangSanFeng();
        zhangSanFeng.finghting();
    }
}

模板方法模式的使用场景和优缺点

  • 使用场景
  1. 多个子类有共有的方法,并且逻辑基本相同时。
  2. 面对重要,复杂的算法,可以把核心算法设计为模板方法,周边相关细节功能则由各个子类实现
  3. 需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制
  • 优点
  1. 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
  2. 子类实现算法的某些细节,有助于算法的扩展
  • 缺点
  1. 每个不同的实现都需要定义一个子类,这会导类的个数的增加,设计更加抽象。

借鉴刘望舒《Android进阶之光》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

万子开发

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

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

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

打赏作者

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

抵扣说明:

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

余额充值