14.模板方法模式

1. 豆浆制作问题

编写制作豆浆的程序, 说明如下:

1 . 制作豆浆的流程:选材—>添加配料—>浸泡—>放到豆浆机打碎
2 . 通过添加不同的配料, 可以制作出不同口味的豆浆
3. 选材、 浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
4 . 请使用模板方法模式完成 (说明:因为模板方法模式,比较简单,很容易就想到这个方案, 因此就直接使用,不再使用传统的方案来引出模板方法模式)

2. 模板方法模式基本介绍

  • 模板方法模式(Template Method Pattern) , 又叫模板模式(Template Pattern), 在一个抽象类公开定义了执行它的方法的模板,它的子类可以按需要重写方法实现, 但调用将以抽象类中定义的方式进行

  • 简单说, 模板方法模式定义一个操作中的算法(流程)的骨架, 而将一些步骤延迟到子类中, 使得子类可以不改变一个算法的结构, 就可以重定义该算法的某些特定步骤
    模板方法设计模式属于行为型模式

3. 模板方法模式原理类图

AbstractClass为抽象类, 类中实现了template()模板方法, 该方法定义了算法的骨架, 具体子类需要去实现抽象方法operation 2,3,4
ConcreteClass实现抽象方法operation 2,3,4以完成算法中特定子类的步骤
在这里插入图片描述

4. 模板方法模式解决豆浆制作问题

应用实例要求:

1 . 对于编写制作豆浆的程序, 说明如下:
2 . 制作豆浆的流程:选材—>添加配料—>浸泡—>放到豆浆机打碎
3. 通过添加不同的配料, 可以制作出不同口味的豆浆
4 . 选材、 浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的

在这里插入图片描述
SoyaMilk:抽象类,定义制作豆浆的模板方法,对于不同口味的豆浆,子类重写 addCondiments() 方法即可

package seven_big_principle.desgin_model_23.template;


/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021/09/25/21:05
 * @Description: 抽象类(表示豆浆)
 */
public abstract class SoyaMilk {
    
    

    /**
     *  制作豆浆的模板方法 :可以做一个代码的运行时长计算
     */
    final  void make(){
    
    
        long start=System.currentTimeMillis();
        // 1.选材
        select();
        // 2.添加配料
        addCondiment();
        // 3.浸泡
        soak();
        // 4.打豆浆
        beat();
        while (true){
    
    
            try {
    
    
                Thread.sleep(10);
                break;
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        long stop=System.currentTimeMillis()-start;

        System.out.println("程序花费时长: "+stop);
    }

    // 1.选材
    void select(){
    
    
        System.out.println("第一步:选择新鲜的黄豆");
    }

    // 2.添加不同的配料,制作不同口味的豆浆 有子类去实现
    abstract void addCondiment();

    // 3.浸泡
    void soak(){
    
    
        System.out.println("第三步:黄豆开始浸泡一段时间");
    }

    // 4.开始打豆浆
    void beat(){
    
    
        System.out.println("第四步:将黄豆放入到豆浆机打碎");
    }


}

RedBeanSoyaMilk:红豆口味的豆浆,重写 addCondiments() 方法,添加红豆即可

package seven_big_principle.desgin_model_23.template;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021/09/25/21:33
 * @Description: 制作红豆豆浆类
 */
public class RedSoyaMilk extends SoyaMilk {
    
    
    // 2.添加不同的配料,制作不同口味的豆浆
    @Override
    void addCondiment() {
    
    
        System.out.println("第二步:加入上好的红豆");
    }
}

PeanutSoyaMilk:花生口味的豆浆,重写 addCondiments() 方法,添加花生即可

package seven_big_principle.desgin_model_23.template;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021/09/25/21:34
 * @Description: 制作花生豆浆类
 */
public class PeauntSoyaMilk extends SoyaMilk{
    
    
    // 2.添加不同的配料,制作不同口味的豆浆
    @Override
    void addCondiment() {
    
    
        System.out.println("第二步:加入上好的花生");
    }
}

Client:客户端 (测试程序)

package seven_big_principle.desgin_model_23.template;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021/09/25/21:35
 * @Description: 客户端 :调用者
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        // 制作花生豆浆
        SoyaMilk peauntSoyaMilk = new PeauntSoyaMilk();
        peauntSoyaMilk.make();

        System.out.println("------------分割线------------");
        // 制作红豆豆浆
        SoyaMilk redSoyaMilk = new RedSoyaMilk();
        redSoyaMilk.make();

    }
}

5.钩子方法

  • 在模板方法模式的父类中, 我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”
  • 还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料, 请使用钩子方法对前面的模板方法进行改造。

代码实现:

SoyaMilk:添加 customerWantCondiments() 方法用于判断是否需要添加配料

package seven_big_principle.desgin_model_23.template.improve;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import org.w3c.dom.ls.LSOutput;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-09-25-22:10
 * @Version:1.0
 * @Description:
 */
public abstract class SoyaMilk {
    
    
    // 模板方法,直接调用本类的方法去完成豆浆的制作
    final void make() {
    
    
        //1.选材
        select();

        //2.添加配料之前进行判断 是否添加配料
        if (customerWantCondition()){
    
    
            addCondiment();
        }

        //3.浸泡
        soak();
        //4.放到豆浆机打碎
        beat();
    }

    //1.选材
    void select() {
    
    
        System.out.println("第一步:选择上好的黄豆");
    }

    //2.添加配料
    abstract void addCondiment();

    //3.浸泡
    void soak() {
    
    
        System.out.println("第三步:将黄豆浸泡一会儿");
    }

    //4.放到豆浆机打碎
    void beat() {
    
    
        System.out.println("第四步:将黄豆都碎制作成豆浆");
    }

    boolean customerWantCondition( ){
    
    
        return true;
    }
}

PureSoyaMilk:纯豆浆无需添加任何配料,

package seven_big_principle.desgin_model_23.template.improve;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-09-25-22:26
 * @Version:1.0
 * @Description: 制作纯豆浆类
 * 一个很妙的思路就是:addCondiment()方法空实现,就代表着该类中的豆浆不要添加任何配料,
 * 然后再重写customerWantCondition()方法返回false就行,不去调用添加配料的方法
 */
public class PureSoyaMilk  extends SoyaMilk{
    
    
    @Override
    void addCondiment() {
    
    
        // 空实现
    }

    @Override
    boolean customerWantCondition() {
    
    
        // 返回false 表示不需要添加任何配料
        return false;
    }
}

Client:客户端(用于测试)

package seven_big_principle.desgin_model_23.template.improve;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-09-25-22:10
 * @Version:1.0
 * @Description: 客户端(测试所用)
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        SoyaMilk redSoyaMilk = new RedSoyaMilk();
        redSoyaMilk.make();

        System.out.println("-----------分割线-----------");

        SoyaMilk peauntSoyaMilk = new PeauntSoyaMilk();
        peauntSoyaMilk.make();

        System.out.println("-----------分割线-----------");

        SoyaMilk pureSoyaMilk = new PureSoyaMilk();
        pureSoyaMilk.make();
    }
}

6. Spring 框架中的模板方法模式

在这里插入图片描述

7 . 模板方法模式的注意事项

模板方法模式的注意事项和细节

  • 基本思想是:将算法的具体实现流程编写在抽象父类中,某些具体的方法实现由子类重写。 需要修改算法时, 只要修改父类的模板方法或者已经实现的某些步骤流程, 子类就会继承这些修改
  • 实现了最大化代码复用。 父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
  • 既统一了算法, 也提供了很大的灵活性。 父类的模板方法确保了算法的结构保持不变, 同时由子类提供部分步骤的实现。
  • 该模式的不足之处: 每一个不同的具体实现都需要一个子类实现, 导致类的个数增加, 使得系统更加庞大
  • 一般模板方法都加上final关键字, 防止子类重写模板方法
  • 模板方法模式使用场景: 当要完成在某个过程, 该过程要执行一系列步骤 , 这一系列的步骤基本相同, 但其个别步骤在实现时 可能不同, 通常考虑用模板方法模式来处理

おすすめ

転載: blog.csdn.net/m0_46188681/article/details/120478370