笨蛋学设计模式行为型模式-模板方法模式【17】

发布时间:2024年01月22日

8.4模板方法模式??????

8.4.1概念

? 模板方法模式就是在某个方法中定义了一个算法的骨架,将某些步骤延迟到子类中实现。以此来让子类在不改变算法的结构的情况下重新定制算法的某些行为 / 步骤。

8.4.2场景

? 在我们进行的烹饪的过程中,有些菜肴的制造步骤是固定的,比如炒菜之前要先热锅冷油、加入姜蒜葱爆香,然后加入要炒的备菜,最后放入调料调味进行翻炒,然后出锅。不同的菜肴可能只需要在某些步骤上有所差异,比如加入的调料不同,要炒的备菜不同。这种情况下,就可以使用模板方法模式,先定义一个基本的烹饪流程(模板方法),然后让不同的菜肴根据需求实现不同的细节(抽象方法)。

8.4.3优势 / 劣势

  • 代码复用性:模板方法模式通过将一些通用的代码放在父类中,避免了代码的重复编写
  • 抽象化:模板方法模式提供了一种抽象化的方式,使得子类可以在不改变算法结构的情况下定制算法的某些行为
  • 稳定性:模板方法模式可以使得子类在不改变整体结构的情况下修改某些细节

  • 代码复杂性:若模板方法模式被过度使用,可能会导致继承层次过深
  • 过度特殊化:模板方法模式可能会导致过度特殊化,使得子类数量过多,反而增加了维护的难度

8.4.4模板方法模式可分为

  • 模板类AbstractClass:由一个模板方法和若干个基本方法构成,模板方法定义了逻辑的骨架,按照顺序调用包含的基本方法,基本方法通常是一些抽象方法,这些方法由子类去实现。基本方法还包含一些具体方法,它们是算法的一部分,但已经有默认实现,在具体子类中可以继承或重写。
  • 具体类ConcreteClass:继承自模板类,实现了在模板类中定义的抽象方法,以完成算法中特定步骤的具体实现。

8.4.5模板方法模式

package com.technologystatck.designpattern.mode.template;

public class Templates {
    public static void main(String[] args) {
        AbstractClass concreteTemplate = new ConcreteClass();

        //触发整个算法的执行
        concreteTemplate.templateMethod();
    }
}

//定义模板类,包含模板方法,定义了算法的骨架,
//一般都加上final关键字,避免子类重写
//模板类
abstract class AbstractClass{
    //模板方法,定义了算法的骨架
    public final void templateMethod(){
        step1();
        step2();
        step3();
    }

    //抽象方法,由子类实现
    protected abstract void step1();
    protected abstract void step2();
    protected abstract void step3();
}

//定义具体类,实现模板类中的抽象方法
//具体类
class ConcreteClass extends AbstractClass{

    @Override
    protected void step1() {
        System.out.println("Step 1");
    }

    @Override
    protected void step2() {
        System.out.println("Step 2");
    }

    @Override
    protected void step3() {
        System.out.println("Step 3");
    }
}

8.4.6实战

8.4.6.1题目描述

小明喜欢品尝不同类型的咖啡,她发现每种咖啡的制作过程有一些相同的步骤,他决定设计一个简单的咖啡制作系统,使用模板方法模式定义咖啡的制作过程。系统支持两种咖啡类型:美式咖啡(American Coffee)和拿铁(Latte)。

咖啡制作过程包括以下步骤:

  1. 研磨咖啡豆 Grinding coffee beans
  2. 冲泡咖啡 Brewing coffee
  3. 添加调料 Adding condiments

其中,美式咖啡和拿铁的调料添加方式略有不同, 拿铁在添加调料时需要添加牛奶Adding milk

8.4.6.2输入描述

多行输入,每行包含一个数字,表示咖啡的选择(1 表示美式咖啡,2 表示拿铁)。

8.4.6.3输出描述

根据每行输入,输出制作咖啡的过程,包括咖啡类型和各个制作步骤,末尾有一个空行。

8.4.6.4代码
package com.technologystatck.designpattern.mode.template;

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        while(scanner.hasNext()){
            int coffeeType = scanner.nextInt();

            CoffeeMarkerTemplate coffeeMarkerTemplate = null;

            if(coffeeType == 1){
                coffeeMarkerTemplate = new AmericanoCoffeeMarker();
            } else if (coffeeType == 2) {
                coffeeMarkerTemplate = new LatteCoffeeMarker();
            }else {
                System.out.println("Invalid coffee type");
                continue;
            }
            //制作咖啡
            coffeeMarkerTemplate.makeCoffee();
        }
    }
}

//抽象类
abstract class CoffeeMarkerTemplate{
    //添加咖啡名称字段
    private String coffeeName;

    //构造函数,接受咖啡名称参数
    public CoffeeMarkerTemplate(String coffeeName){
        this.coffeeName=coffeeName;
    }

    //模板方法定义咖啡制作过程
    final void makeCoffee(){
        System.out.println("Making "+coffeeName+":");
        grindCoffeeBeans();
        brewCoffee();
        addCondiments();
        System.out.println();
    }

    //具体步骤的具体实现由子类提供
    abstract void grindCoffeeBeans();
    abstract void brewCoffee();

    //添加调料的默认实现
    void addCondiments(){
        System.out.println("Adding condiments");
    }
}

//具体的美式咖啡类
class AmericanoCoffeeMarker extends CoffeeMarkerTemplate{

    //构造函数传递咖啡名称,这里使用了父类的构造函数,
    public AmericanoCoffeeMarker() {
        super("American Coffee");
    }

    @Override
    void grindCoffeeBeans() {
        System.out.println("Grinding coffee beans");
    }

    @Override
    void brewCoffee() {
        System.out.println("Brewing coffee");
    }
}

//具体的拿铁咖啡类
class LatteCoffeeMarker extends CoffeeMarkerTemplate{

    //构造函数传递咖啡名称,这里使用了父类的构造函数,
    //并传递了咖啡名称参数
    public LatteCoffeeMarker() {
        super("Latte");
    }

    //构造函数传递咖啡名称
    @Override
    void grindCoffeeBeans() {
        System.out.println("Grinding coffee beans");
    }

    @Override
    void brewCoffee() {
        System.out.println("Brewing coffee");
    }

    //添加调料的特定实现
    void addCondiments(){
        System.out.println("Adding milk");
        System.out.println("Adding condiments");
    }
}

8.4.7总结

  • 优点:封装通用算法流程,避免重复代码,可以方便增加新的算法实现
  • 总结:定义一个抽象类用作于骨架,定义一个具体类用于实现抽象类中的抽象方法完善整个身体
  • 场景:将算法的不变部分被封装在模板方法中,而可变部分算法由子类继承实现时
文章来源:https://blog.csdn.net/YSL_Monet/article/details/135736735
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。