什么是模板模式(Template)?应用场景是什么?

本文介绍模板模式的概念、使用场景及其实现方法。通过烹饪实例展示如何利用模板模式定义算法骨架,并允许子类重定义某些步骤而不改变整体流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Template模板模式:一个抽象类公开定义了执行它的方法的方式/模板,它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
通俗来说,可以这样理解: 定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。
比如:完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。

抽象父类(AbstractClass):实现了模板方法,定义了算法的骨架。
具体类(ConcreteClass):实现抽象类中的抽象方法,即不同的对象的具体实现细节。
我们看如下代码:

package Paint;
//抽象父类
public abstract class DodishTemplate {
    /**
     * 具体的整个过程
     */
    protected void dodish() {
        this.preparation();
        this.doing();
        this.carriedDishes();
    }

    /**
     * 备料
     */
    public abstract void preparation();

    /**
     * 做菜
     */
    public abstract void doing();

    /**
     * 上菜
     */
    public abstract void carriedDishes();
}
package Paint;

/**
 * 子类:西红柿炒蛋
 */
public class EggsWithTomato extends DodishTemplate {

    @Override
    public void preparation() {
        System.out.println("洗并切西红柿,打鸡蛋。");
    }

    @Override
    public void doing() {
        System.out.println("鸡蛋倒入锅里,然后倒入西红柿一起炒。");
    }

    @Override
    public void carriedDishes() {
        System.out.println("将炒好的西红寺鸡蛋装入碟子里,端给客人吃。");
    }

}
package Paint;

/**
 * 子类:红烧肉
 */
public class Bouilli extends DodishTemplate {

    @Override
    public void preparation() {
        System.out.println("切猪肉和土豆。");
    }

    @Override
    public void doing() {
        System.out.println("将切好的猪肉倒入锅中炒一会然后倒入土豆连炒带炖。");
    }

    @Override
    public void carriedDishes() {
        System.out.println("将做好的红烧肉盛进碗里端给客人吃。");
    }

}
package Paint;
// 测试
public class TestCooking {
    public static void main(String[] args) {
        DodishTemplate eggsWithTomato = new EggsWithTomato();
        eggsWithTomato.dodish();

        System.out.println("-----------------------------");

        DodishTemplate bouilli = new Bouilli();
        bouilli.dodish();
    }
}

// 执行结果如下:
#洗并切西红柿,打鸡蛋。
#鸡蛋倒入锅里,然后倒入西红柿一起炒。
#将炒好的西红寺鸡蛋装入碟子里,端给客人吃。
#-----------------------------
#切猪肉和土豆。
#将切好的猪肉倒入锅中炒一会然后倒入土豆连炒带炖。
#将做好的红烧肉盛进碗里端给客人吃。

模板设计模式看代码,不难理解,在加载配置文件的时候,可以有不同的加载方式,如根据文件系统目录加载配置文件(FileSystemXmlApplicationContext),类路径加载配置文件(ClassPathXmlApplicationContext),以及根据项目上下文目录(XmlWebApplicationContext)加载配置文件。
这个在加载的过程中就使用了模板设计模式,模板设计模式的意图:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

主要解决:一些方法通用,却在每一个子类都重新写了这一方法。

何时使用:有一些通用的方法。

如何解决:将这些通用算法抽象出来。

关键代码:在抽象类实现,其他步骤在子类实现。

优点:
1、封装不变部分,扩展可变部分。具体细节步骤实现定义在子类中,子类定义详细处理算法是不会改变算法整体结构
2、提取公共代码,便于维护。代码复用的基本技术,在数据库设计中尤为重要。
3、行为由父类控制,子类实现。存在一种反向的控制结构,通过一个父类调用其子类的操作,通过子类对父类进行扩展增加新的行为,符合“开闭原则”。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。

注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。

更多设计模式,我们可以到该网站学习:
http://www.runoob.com/design-pattern/template-pattern.html

<think>嗯,用户想了解模板方法模式的概念和用法。首先,我需要回忆一下模板方法模式的基本定义。根据引用[1],模板方法模式属于行为设计模式,它在抽象类中定义算法骨架,将某些步骤延迟到子类实现。这样可以在不改变结构的情况下重定义某些步骤。接下来,用户可能想知道这个模式的结构。引用[4]提到,模板方法模式有一个抽象类,包含模板方法和基本方法。模板方法是算法的骨架,由抽象类实现,而基本方法分为抽象方法和钩子方法,由子类具体实现。需要举例说明,比如咖啡和茶的制作流程,这样可以更直观。然后,用户可能关心适用场景。引用[1]和[3]指出,当有多个子类共有相同的方法结构,但某些步骤不同时,或者需要扩展算法中的特定步骤时适用。比如游戏开发中的不同关卡初始化步骤,这里可以引用具体的例子来加强理解。 关于优缺点,引用[2]和[4]提到,模板方法模式提高了复用性和扩展性,符合开闭原则,但每个不同实现都需要一个子类,可能导致类数量增加。同时,父类中的方法可能影响子类,需要权衡。 实现部分,需要给出代码示例。根据引用[1],抽象类定义模板方法,子类实现抽象方法。比如制作饮料的例子,抽象类有prepareBeverage()作为模板方法,包含boilWater、brew、addCondiments等步骤,子类如Coffee和Tea分别实现brew和addCondiments。 还要注意与策略模式的区别,引用[2]提到模板方法使用继承,策略使用组合,这点需要说明,避免混淆。 最后,生成相关问题,帮助用户深入理解。比如适用场景、优缺点、与策略模式的区别,以及实际应用案例。这样用户可以有方向地进一步学习。</think>### 模板方法模式的概念及实现 #### 一、概念 模板方法模式是一种**行为设计模式**,它通过以下方式工作: 1. **定义算法框架**:在抽象类中定义一个操作的算法骨架(即模板方法),将部分步骤的实现延迟到子类中[^1][^4]。 2. **代码复用与扩展**:子类在不改变算法结构的前提下,可以重写某些步骤的具体实现,例如: - 抽象步骤:必须由子类实现的方法。 - 钩子方法:子类可选择覆盖的方法,用于控制算法流程[^3][^4]。 #### 二、实现步骤 1. **抽象类定义模板方法**: ```java public abstract class AbstractClass { // 模板方法(不可被重写) public final void templateMethod() { step1(); step2(); if (hookMethod()) { step3(); } } // 基本方法(抽象步骤) protected abstract void step1(); // 默认实现(钩子方法) protected void step2() { System.out.println("默认步骤2"); } // 钩子方法(控制流程) protected boolean hookMethod() { return true; } // 具体步骤 private void step3() { System.out.println("固定步骤3"); } } ``` 2. **子类实现具体逻辑**: ```java public class ConcreteClassA extends AbstractClass { @Override protected void step1() { System.out.println("子类A的步骤1"); } @Override protected boolean hookMethod() { return false; // 关闭步骤3的执行 } } ``` #### 三、适用场景 1. **多子类共享相同流程**:如不同游戏的关卡初始化流程(加载资源→生成敌人→设置背景)[^3]。 2. **扩展算法特定步骤**:例如支付流程中,支付方式(支付宝/微信)不同,但支付验证和日志记录逻辑一致[^1][^4]。 3. **框架设计**:框架定义通用流程,开发者填充具体实现(如Spring的JdbcTemplate)[^2]。 #### 四、优缺点对比 | **优点** | **缺点** | |-------------------------|-------------------------| | 提高代码复用性(70%代码复用) | 每个差异需新增子类(类膨胀) | | 符合开闭原则(扩展步骤不影响框架) | 父类方法限制子类灵活性 | | 封装不变部分,隔离变化部分 | 过度继承可能导致复杂继承链 | #### 五、实际应用示例 **场景:文档导出功能** - **模板方法**:`exportDocument()` 包含步骤:生成数据→格式化→压缩→保存。 - **子类扩展**: - `PDFExporter`:重写格式化方法为PDF生成。 - `ExcelExporter`:重写压缩方法为ZIP加密。 ```python class DocumentExporter(ABC): def export(self): self._fetch_data() self._format() self._compress() self._save() def _fetch_data(self): print("从数据库读取数据") @abstractmethod def _format(self): pass def _compress(self): print("默认压缩为ZIP") def _save(self): print("保存到云存储") class PDFExporter(DocumentExporter): def _format(self): print("生成PDF文件") def _compress(self): print("使用高压缩率算法") ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值