前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >模板方法模式.

模板方法模式.

作者头像
JMCui
发布2018-12-28 16:29:59
4050
发布2018-12-28 16:29:59
举报
文章被收录于专栏:JMCuiJMCui

一、概念

  • 模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
  • 解析:模板方法模式用来创建一个算法的模板。什么是模板?模板就是一个方法。更具体地说,这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现。这可以确保算法的结构保持不变,同时由子类提供部分实现。
  • 角色:  1、抽象模板(Abstract Template):定义模板方法,规范了一组步骤,其中父类可以实现其中的某些步骤,需要由子类实现的步骤声明为 abstract。  2、具体模板(Concrete Template):继承抽象父类,实现抽象父类中声明为 abstract 的方法。
avatar
avatar

二、Demo 实现

我们打算定义一个咖啡因饮料冲泡流程,把流程中相同的步骤放在一起,同时,不同的饮料还能有自己的具体实现。

1、抽象模板

代码语言:javascript
复制
public abstract class CaffeineBeverage {

    /**
     * @Description 
     * 1、模板方法,定义算法的步骤。
     * 2、我们一般把模板方法定义成 final,不希望子类覆盖。
     */
    public final void prepareRecipe() {
        //1、把水煮沸
        boilWater();
        //2、用热水泡饮料(具体什么饮料未知)
        brew();
        //3、把饮料倒进杯子
        pourIncup();
        //4、往饮料中添加调料(具体什么调料未知)
        if (wantAddCondiments()) {
            addCondiments();
        }

    }

    /**
     * @Description 需要子类提供实现的步骤定义为抽象
     */
    protected abstract void brew();

    protected abstract void addCondiments();

    /**
     * @Description 由父类提供实现,又不希望被子类重写的,封装成 private。
     */
    private void boilWater() {
        System.out.println("Boiling water");
    }

    private void pourIncup() {
        System.out.println("Pouring into cup");
    }


    /**
     * @Description 钩子方法
     * 1、钩子是一种被声明在抽象类中的方法,当只有空的或者默认的实现。
     * 2、钩子的存在,可以让子类有能力对算法的不同点进行挂钩(重写)。
     * 3、要不要挂钩(重写),由子类自己决定。
     */
    protected boolean wantAddCondiments() {
        return true;
    }
}

这里,我们定义了一个抽象模板,规范了具体的冲泡流程 —— 把水煮沸->泡饮料->倒杯子->添加调料。在抽象模板中,我们有三种类型的方法,一种需要子类提供实现的,我们定义为 abstract ;一种父类提供实现,又不希望被子类覆盖的,我们定义为 private;还有一种称为钩子方法,父类提供默认实现,子类可自由选择是否重写父类的方法。

2、具体模板

代码语言:javascript
复制
public class Coffee extends CaffeineBeverage {
    @Override
    protected void brew() {
        System.out.println("Dripping Coffee through filter");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding Suger and Milk");
    }
}
代码语言:javascript
复制
public class Tea extends CaffeineBeverage {

    @Override
    protected void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding Lemon");
    }

    /**
    * @Description 子类重写钩子方法
    */
    @Override
    protected boolean wantAddCondiments() {
        return false;
    }
}

具体模板继承了抽象模板,实现了抽象模板中定义为 abstract 的步骤方法,并可以自己选择是否重写钩子方法。

3、测试

代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {
        CaffeineBeverage coffee = new Coffee();
        CaffeineBeverage tea = new Tea();
        coffee.prepareRecipe();
        tea.prepareRecipe();
    }
}
avatar
avatar

三、总结

  • 模板方法模式的通用类图非常简单,仅仅使用了Java的继承机制,但它是一个非常广泛的模式。
  • 优点:  1、封装不变部分,扩展可变部分。把认为不变部分的算法封装到父类中实现,而可变部分的则可以通过继承来继续扩展。可以将代码最大复用化。  2、父类规范算法行为,子类提供完整实现。
  • 使用场景:  1、多个子类有共有的方法,并且逻辑基本相同。  2、一次性实现一个算法的不变部分,并且将可变的行为留给子类来完成。
  • 为防止子类改变模板方法中的算法,可以将模板方法声明为 final。
  • 策略模式和模板方法模式都封装算法,但是策略模式使用的是组合,模板方法模式使用的是继承。
  • 工厂方法是模板方法的一种特殊版本。
  • 低层组件可以调用高层组件中的方法(实际上子类会常常调用其从父类中继承所来的方法),但是我们要做的是要避免让高层和底层组件之间有明显的环状依赖
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、概念
  • 二、Demo 实现
    • 1、抽象模板
      • 2、具体模板
        • 3、测试
        • 三、总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档