ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模版方法模式(模版模式)初体验和总结

2021-08-15 01:04:11  阅读:170  来源: 互联网

标签:初体验 模版 void System 模式 子类 println 方法 public


模版方法模式,也叫做模版模式,是一种行为型模式:

    1. 定义一个算法骨架,并允许子类为为其中的一个或者多个步骤提供实现。
    1. 模版方法使得子类在不改变算法结构的情况下,重新定义算法的某些步骤。可以使用钩子方法,让子类去实现细节,钩子可以让子类有能力为其抽象类做一些决定。
    1. 模版模式可以在抽象父类定义统一的方法,减少代码重复。

模版方法模式举例

比如制作饮料的场景:泡咖啡和泡蜂蜜绿茶

  • 泡咖啡: 1. 先要烧开水 2. 冲泡咖啡 3. 将咖啡倒入到杯子中 4. 加入糖和牛奶
  • 泡蜂蜜绿茶: 1. 先要烧开水 2. 浸泡茶叶 3. 将茶水倒入杯子中 4. 放入少量蜂蜜

发现他们有几个动作是一样的,比如都要烧开水,都要冲泡,都要倒入杯子中,都要放入一些调味品,那这几个动作就可以抽象,用模版模式来实现

1. 首先创建个抽象类,定义类: AbstractMakeDrinkHandler ,制作饮料的抽象类
/**
 * 制作饮料的抽象类
 */
abstract class AbstractMakeDrinkHandler {

    final void makeDrinkStart() {
        //1.把水煮沸
        boilWater();
        //2.独特的浸泡方法
        soakMaterial();
        //3.倒入茶杯
        pourTeacup();
        //4.加入调味品
        addSeasoning();
    }

    /**
     * 烧开水方法
     */
    void boilWater() {
        System.out.println("开始烧水");
    }

    /**
     * 抽象的冲泡方法,由子类实现细节
     */
    protected abstract void soakMaterial();

    /**
     * 倒入茶杯的方法
     */
    void pourTeacup() {
        System.out.println("将饮料倒入杯子中");
    }

    /**
     * 加入调味品的方法,由子类实现细节
     */
    protected abstract void addSeasoning();
}

这里由于烧开水方法和倒入茶杯的方法是一样的,可以抽象成公共的逻辑放在父类中,冲泡方法和加入调味品的方法定义为抽象方法,由子类来实现具体细节
2. 创建泡咖啡类和泡蜂蜜绿茶类
制作咖啡类
/**
 * 制作咖啡类
 */
public class MarkCoffeeHandler extends AbstractMakeDrinkHandler {

    @Override
    protected void soakMaterial() {
        System.out.println("用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟");
    }

    @Override
    protected void addSeasoning() {
        System.out.println("咖啡里加点糖和牛奶");
    }

}

制作绿茶类
/**
 * 制作绿茶类
 */
public class MarkTeaHandler extends AbstractMakeDrinkHandler {

    @Override
    protected void soakMaterial() {
        System.out.println("用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟");
    }


    @Override
    protected void addSeasoning() {
        System.out.println("茶里加点蜂蜜");
    }

}
main方法
public class MainClass {

    public static void main(String[] args) {
        //制作咖啡
        MarkCoffeeHandler coffeeHandler = new MarkCoffeeHandler();
        coffeeHandler.makeDrinkStart();
        System.out.println("=======================");
        //制作绿茶
        MarkTeaHandler teaHandler = new MarkTeaHandler();
        teaHandler.makeDrinkStart();
    }
}

执行,控制台输出结果
开始烧水
用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟
将饮料倒入杯子中
咖啡里加点糖和牛奶
=======================
开始烧水
用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟
将饮料倒入杯子中
茶里加点蜂蜜

这里会发现,父类很好的约束了算法的框架,子类对细节进行了实现,父类也把复用的代码进行了抽象

扩展点:

    1. 将饮料倒入杯子中,我想知道具体倒入的是什么饮料,如何知道呢?
    1. 冲泡的时候,根据客户需要,可能是热饮料,也可能是凉的饮料,热的饮料要玻璃杯装,凉的饮料可以用纸杯装,这个如何实现?

这时候,就需要用到钩子方法,由子类来决定要不要继承,来修改父类的行为。更改后的代码如下:

/**
 * 制作饮料的抽象类
 */
abstract class AbstractMakeDrinkHandler {

    final void makeDrinkStart() {
        //1.把水煮沸
        boilWater();
        //2.用沸水浸泡茶/冲泡咖啡
        soakMaterial();
        //3.倒入茶杯
        pourTeacup();
        //4.加入调料
        addSeasoning();
    }

    /**
     * 烧开水方法
     */
    void boilWater() {
        System.out.println("开始烧水");
    }

    /**
     * 抽象的冲泡方法,由子类实现细节
     */
    protected abstract void soakMaterial();

    /**
     * 倒入茶杯的方法
     */
    void pourTeacup() {
        if (hotDrink()) {
            System.out.println("热饮料需要准备玻璃杯");
        } else {
            System.out.println("准备纸杯");
        }
        System.out.println("将" + getDrinkName() + "倒入杯子中");
    }

    /**
     * 加入调味品的方法,由子类实现细节
     */
    protected abstract void addSeasoning();

    /**
     * 钩子方法,返回饮料的类别
     * @return
     */
    public String getDrinkName() {
        return "饮料";
    }

    /**
     * 钩子方法,返回是冷饮还是热饮
     * @return
     */
    public boolean hotDrink() {
        return false;
    }
}
制作咖啡类 和制作绿茶类
/**
 * 制作咖啡类
 */
public class MarkCoffeeHandler extends AbstractMakeDrinkHandler {

    private String drinkName;

    private boolean hotDrink;

    public MarkCoffeeHandler(boolean hotDrink) {
        this.hotDrink = hotDrink;
        this.drinkName = "咖啡";
    }

    @Override
    protected void soakMaterial() {
        System.out.println("用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟");
    }

    @Override
    protected void addSeasoning() {
        System.out.println("咖啡里加点糖和牛奶");
    }

    @Override
    public boolean hotDrink() {
        return this.hotDrink;
    }

    @Override
    public String getDrinkName() {
        return this.drinkName;
    }
}

/**
 * 制作绿茶类
 */
public class MarkTeaHandler extends AbstractMakeDrinkHandler {

    private String drinkName;

    private boolean hotDrink;

    public MarkTeaHandler(boolean hotDrink) {
        this.hotDrink = hotDrink;
        this.drinkName = "绿茶";
    }

    @Override
    protected void soakMaterial() {
        System.out.println("用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟");
    }


    @Override
    protected void addSeasoning() {
        System.out.println("茶里加点蜂蜜");
    }

    @Override
    public String getDrinkName() {
        return this.drinkName;
    }

    @Override
    public boolean hotDrink() {
        return this.hotDrink;
    }
}

main方法
public class MainClass {

    public static void main(String[] args) {
        //制作咖啡
        MarkCoffeeHandler coffeeHandler = new MarkCoffeeHandler(true);
        coffeeHandler.makeDrinkStart();
        System.out.println("=======================");
        //制作绿茶
        MarkTeaHandler teaHandler = new MarkTeaHandler(false);
        teaHandler.makeDrinkStart();
    }
}
执行方法后控制台输出
开始烧水
用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟
热饮料需要准备玻璃杯
将咖啡倒入杯子中
咖啡里加点糖和牛奶
=======================
开始烧水
用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟
准备纸杯
将绿茶倒入杯子中
茶里加点蜂蜜

发现子类通过钩子方法,很好的改变了父类冲泡方法的细节,为是准备玻璃杯还是纸杯提供了决定
关联的类图如下

模版方法模式优点:

    1. 利用模版方法模式把相同逻辑的代码抽象到抽象父类中,提高代码复用性,符合开闭原则
    1. 定义一系列算法框架,子类在不改变算法框架的情况下,扩展新的行为,并且可以通过钩子方法,对父类一些
      算法实现细节做出决定。

模版方法模式缺点:

    1. 类的增加,系统增加复杂度
    1. 继承关系自身缺点,父类添加新的方法,所有子类都要改一遍,依赖关系比组合更强

模版方法在java 中的使用:

    1. jdbcTemplate 类,里面定义了从加载驱动,封装了所有jdbc操作,包括1.建立连接,2.创建语句集 3. 执行语句集 4. 返回结果集 5. 关闭连接
    1. AbstractList 类, 里面定义了通用的 indexOf , lastIndexOf,equals,hashCode()方法,但是get是一个抽象方法,需要通过子类来实现。
    /**
     * {@inheritDoc}
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    abstract public E get(int index);

add 方法,addAll 方法 是钩子方法,由子类决定要不要实现,比如ArrayList ,LinkedList 都有具体的实现

    public boolean add(E e) {
        add(size(), e);
        return true;
    }
   
 public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }
   
    1. HttpServlet 类 , 比如 doGet ,doPost,doPut ,service 等都是模版方法的抽象实现,由子类去实现细节

标签:初体验,模版,void,System,模式,子类,println,方法,public
来源: https://www.cnblogs.com/summerDawn/p/15142401.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有