final+模版设计模式的理解

发布于:2025-03-30 ⋅ 阅读:(22) ⋅ 点赞:(0)

模板设计模式在 Java 里是一种行为设计模式,它在抽象类里定义算法的骨架,把部分步骤的具体实现延迟到子类。如此一来,子类可以在不改变算法结构的基础上,重新定义算法中的特定步骤。

模式组成

抽象类(Abstract Class):定义了算法的骨架,其中包含模板方法与抽象方法。模板方法是具体方法,它规定了算法的步骤,并且会调用抽象方法;抽象方法则由子类去实现。  

具体子类(Concrete Subclass):实现抽象类中的抽象方法,完成算法中特定步骤的具体操作。 代码示例

下面是一个用 Java 实现模板设计模式的示例,以制作饮料为例:

// 抽象类
abstract class Beverage {
    // 模板方法,定义制作饮料的算法骨架
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 抽象方法,由子类实现
    public abstract void brew();

    public abstract void addCondiments();
}

// 具体子类:咖啡
class Coffee extends Beverage {
    @Override
    public void brew() {
        System.out.println("Dripping coffee through filter");
    }

    @Override
    public void addCondiments() {
        System.out.println("Adding sugar and milk");
    }
}

// 具体子类:茶
class Tea extends Beverage {
    @Override
    public void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    public void addCondiments() {
        System.out.println("Adding lemon");
    }
}

// 测试类
public class TemplatePatternDemo {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        System.out.println("Making coffee:");
        coffee.prepareBeverage();

        System.out.println("\nMaking tea:");
        Beverage tea = new Tea();
        tea.prepareBeverage();
    }
}

代码解释

Beverage类属于抽象类,prepareBeverage方法是模板方法,它定义了制作饮料的通用步骤。brew和addCondiments是抽象方法,要由子类来实现。

Coffee和Tea类为具体子类,它们实现了brew和addCondiments方法,完成了制作咖啡和茶的特定步骤。

优点

代码复用:模板方法定义了算法的骨架,避免了在多个子类中重复编写相同的代码。

可扩展性:子类能够根据需求重写抽象方法,实现自身的业务逻辑。

缺点

类数量增加:每一个不同的实现都需要一个子类,这可能会导致类的数量增加,使系统更加复杂。 灵活性受限:由于模板方法定义了算法的骨架,子类只能在特定的步骤上进行扩展,可能会限制算法的灵活性。




public final void prepareBeverage(),final修饰里面的方法,不能重写,里面的方法却能重写,我很混乱,通俗易懂解释一下




在模板方法模式中,prepareBeverage() 被声明为 final 是为了确保算法的整体流程不被子类修改,而内部的 brew() 和 addCondiments() 被声明为 abstract 是为了强制子类实现具体的细节。这种设计实现了“固定流程,灵活扩展”的效果。


通俗解释:

  1. 为什么用 final
    prepareBeverage() 是制作饮料的固定流程(烧水 → 冲泡 → 倒杯 → 加调料),用 final 表示“这个流程不能被子类篡改”。比如,子类不能把顺序改成“先加调料再烧水”。

  2. 为什么内部的 brew() 和 addCondiments() 可以重写?
    这两个方法是抽象方法(abstract),子类必须实现它们。父类只定义流程(“要冲泡”和“要加调料”),但具体怎么冲泡、加什么调料,由子类自己决定。例如:

    • 咖啡冲泡是“用滤纸滴漏”,加“糖和牛奶”。

    • 茶冲泡是“用热水浸泡茶叶”,加“柠檬”。


类比现实场景:

想象一个“烹饪机器人”的模板:

  1. 固定流程(final 方法):
    它的做菜步骤是固定的:开火 → 放食材 → 翻炒 → 关火。

  2. 灵活扩展(抽象方法):
    但具体“放什么食材”、“怎么翻炒”由用户决定(比如做西红柿炒蛋还是青椒肉丝)。


代码验证:

如果子类尝试重写 prepareBeverage(),会直接编译报错:

class Coffee extends Beverage {
    // ❌ 编译错误!不能重写 final 方法
    @Override
    public void prepareBeverage() { 
        // 非法操作!
    }
}

但子类必须实现抽象方法:

class Coffee extends Beverage {
    @Override
    public void brew() { /* 必须实现 */ }      // ✅
    @Override
    public void addCondiments() { /* 必须实现 */ } // ✅
}

总结:

  • final 方法:保护算法流程的完整性(“怎么做”)。

  • abstract 方法:定义子类必须实现的扩展点(“做什么”)。

这就是模板方法模式的核心:在父类控制流程,在子类实现细节