• 设计模式行为型-模板模式


    一:模板方法设计模式概述

    1.1 简介

    模板方法设计模式是一种行为型设计模式,它定义了一个算法的骨架,在其中某些步骤由具体子类来实现。

    1.2 定义和目的

    模板方法设计模式通过将算法通用部分放在抽象类中,具体实现留给具体子类来完成,以提高代码的复用性和可维护性。
    在这里插入图片描述

    1.3 关键特点

    • 模板方法:定义算法的骨架,其中某些步骤由具体子类来实现。
    • 具体方法:抽象类中已经实现的方法,子类不能修改。
    • 钩子方法:抽象类中定义的可选方法,具体子类选择性地覆盖,可以改变模板方法的行为。

    1.4 适用场景

    • 当算法有固定的结构或步骤,并且步骤之间存在关联性时,可以使用模板方法设计模式。
    • 当需要在不同上下文中应用相似的算法时,可以使用模板方法设计模式。
    • 当希望通过基类来控制子类的行为时,可以使用模板方法设计模式。

    二:模板方法设计模式基本原理

    2.1 抽象类

    2.1.1 定义和作用

    抽象类是模板方法设计模式的核心角色,它定义了模板方法和一系列抽象方法,描述算法的结构和步骤。

    2.1.2 模板方法

    模板方法是抽象类中定义的方法,描述算法的骨架。该方法通常是final类型的,以防止子类对其进行修改。

    2.1.3 具体方法

    具体方法是抽象类中已经实现的方法,子类不能修改。这些方法通常是模板方法所需要的辅助方法或公共方法。

    2.2 具体类

    2.2.1 定义和作用

    具体类是抽象类的子类,负责实现抽象类中的抽象方法,完成算法的具体实现。

    2.2.2 实现抽象类中的抽象方法

    具体类需要实现抽象类中定义的抽象方法,完成算法的具体实现。

    2.2.3 覆盖钩子方法

    具体类可以选择性地覆盖抽象类中定义的钩子方法,以改变模板方法的行为。

    三:模板方法设计模式实现步骤

    3.1 创建抽象类

    3.1.1 声明模板方法

    在抽象类中声明模板方法,描述算法的骨架。通常将该方法设置为final类型,防止子类修改。

    3.1.2 定义具体方法

    在抽象类中定义具体方法,这些方法在模板方法中被调用。这些方法通常是私有或受保护的,不允许子类直接调用。

    3.1.3 定义钩子方法

    定义可选的钩子方法,根据需要提供默认实现或为空实现。具体子类可以选择性地覆盖这些方法以改变模板方法的行为。

    3.2 创建具体类

    3.2.1 实现抽象类中的抽象方法

    创建具体类并实现抽象类中的抽象方法,完成算法的具体实现。

    3.2.2 覆盖钩子方法

    具体类可以选择性地覆盖抽象类中的钩子方法,以改变模板方法的行为。

    四:模板方法设计模式应用场景

    4.1 实际案例背景介绍

    假设我们正在开发一个游戏,这个游戏中有多个角色,每个角色都有不同的行为和技能。我们需要设计一个通用的角色创建流程,以确保每个角色的创建过程都符合一定的规范和约束。这就是一个适用于模板方法设计模式的实际案例。

    4.2 设计模式解决方案

    我们可以使用模板方法设计模式来解决上述问题。首先,我们创建一个抽象类作为角色的基类,其中包含了一个模板方法用于控制角色的创建流程。具体的角色类继承这个抽象类,并实现其中的抽象方法来完成自己特定的行为和技能。

    在抽象类中,我们可以定义一些公共的方法,比如角色的初始化方法、资源加载方法等,这些方法已经实现并且不允许子类修改。同时,我们也可以定义一些钩子方法,用于在角色创建的不同阶段插入一些额外的逻辑。

    抽象类中的模板方法定义了角色的创建流程,它按照一定的顺序调用了一系列的具体方法和钩子方法。这些具体方法和钩子方法由具体的角色类来实现,根据不同的需求来完成具体的行为和技能。

    通过使用模板方法设计模式,我们可以将公共的部分提取到抽象类中,实现了代码的复用和可维护性的提高。同时,具体的角色类也能够灵活地实现自己特定的行为和技能,满足了游戏中多样化的角色需求。

    4.3 实现代码示例

    下面是一个简单的实现代码示例,演示了如何使用模板方法设计模式来创建游戏角色:

    // 抽象类:角色
    public abstract class Character {
        // 模板方法:创建角色
        public final void createCharacter() {
            initialize();   // 初始化角色
            loadResources();    // 加载资源
            doSomething();  // 具体行为
            hookMethod();   // 钩子方法
        }
        
        // 具体方法:初始化角色
        private void initialize() {
            System.out.println("Initializing character...");
        }
        
        // 具体方法:加载资源
        private void loadResources() {
            System.out.println("Loading resources...");
        }
        
        // 抽象方法:具体行为
        protected abstract void doSomething();
        
        // 钩子方法:可选的逻辑
        protected void hookMethod() {
            // 默认为空实现,子类可选择性地覆盖
        }
    }
    
    // 具体类:战士角色
    public class WarriorCharacter extends Character {
        @Override
        protected void doSomething() {
            System.out.println("Warrior is fighting!");
        }
    }
    
    // 具体类:法师角色
    public class MageCharacter extends Character {
        @Override
        protected void doSomething() {
            System.out.println("Mage is casting spells!");
        }
    }
    
    // 测试代码
    public class Main {
        public static void main(String[] args) {
            Character warrior = new WarriorCharacter();
            warrior.createCharacter();   // 输出:Initializing character... Loading resources... Warrior is fighting!
            
            Character mage = new MageCharacter();
            mage.createCharacter();  // 输出:Initializing character... Loading resources... Mage is casting spells!
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    在上面的示例中,Character 是抽象类,其中的 createCharacter() 方法是模板方法,控制了角色的创建流程。具体的角色类 WarriorCharacterMageCharacter 继承了 Character 并实现了其中的抽象方法 doSomething(),完成了自己特定的行为。最后,在 Main 类中测试了这两个具体的角色类的创建过程。

    通过运行上述代码示例,你可以看到不同角色的创建流程遵循了模板方法定义的骨架,但同时具体的角色类可以根据自身的需求实现不同的行为和技能。这就是模板方法设计模式的应用。

    五:模板方法设计模式应用注意事项

    5.1 钩子方法的使用场景和注意事项

    钩子方法是在模板方法设计模式中的一种特殊方法,它在抽象类中提供了一个默认的空实现,子类可以选择性地覆盖或扩展这个方法。钩子方法的主要作用是允许子类在模板方法的特定点插入自己的逻辑,以实现对算法的定制和扩展。

    使用钩子方法可以使得模板方法更加灵活和可扩展,同时也可以避免在抽象类中定义过多的抽象方法,简化了子类的实现。

    一般来说,钩子方法的使用场景包括但不限于以下几种情况:

    1. 选择性执行:某些步骤在特定条件下需要执行,而在其他条件下可以跳过,钩子方法可以判断这些条件并决定是否执行相应步骤。
    2. 扩展功能:在模板方法的特定点添加新的逻辑或功能,用于满足不同的需求。
    3. 改变顺序:通过覆盖或扩展钩子方法,改变模板方法中步骤的执行顺序。

    在使用钩子方法时,需要注意以下几点:

    1. 钩子方法的命名:钩子方法应该具有描述性的、能够体现其作用的命名,以便子类理解和正确使用。
    2. 钩子方法的默认实现:钩子方法在抽象类中应该有一个默认的空实现,以保证子类可以选择是否覆盖它。
    3. 钩子方法的调用时机:钩子方法应该在适当的时机被调用,以确保它们的逻辑能够正确地插入到模板方法中。

    5.2 与其他设计模式的关系

    模板方法设计模式与其他设计模式之间存在一些关系和区别。下面是一些常见的与模板方法设计模式相关的设计模式:

    1. 工厂方法模式(Factory Method Pattern):工厂方法模式也是一种创建型设计模式,它将对象的创建延迟到子类中进行。在工厂方法模式中,模板方法用于定义对象的创建过程,具体的产品由子类来实现。可以说,工厂方法模式是模板方法设计模式在创建对象方面的一种应用。
    2. 策略模式(Strategy Pattern):策略模式用于封装一系列的算法,并使它们可以互相替换。在策略模式中,每个算法都是一个独立的类,而模板方法则是在抽象类中定义的一系列步骤。可以说,策略模式是模板方法设计模式在算法封装方面的一种应用。

    需要注意的是,模板方法设计模式和以上提到的设计模式并不是相互排斥的关系,它们可以结合使用来解决复杂的问题。在实际开发中,根据具体的需求和场景选择合适的设计模式,能够更好地设计和实现高质量的代码。

    5.3 使用建议和最佳实践

    以下是一些使用模板方法设计模式的建议和最佳实践:

    1. 合理划分抽象类和具体类:抽象类应该包含公共的行为和模板方法,具体类应该实现自己特定的行为。
    2. 提取公共的方法和逻辑:将公共的方法和逻辑提取到抽象类中,以避免代码的重复和冗余。
    3. 明确模板方法的执行流程:定义好模板方法的执行顺序,并确保每个步骤的执行时机正确。
    4. 合理使用钩子方法:在需要灵活定制或扩展的地方使用钩子方法,但不要滥用。过多的钩子方法可能导致代码难以理解和维护。
    5. 考虑模板方法的可变性:模板方法应该具有一定的可变性,以便子类可以根据自身需要进行定制。但同时也要保持模板方法的稳定性和一致性。

    结语

    模板方法设计模式是一种行为设计模式,它通过定义一个算法的骨架,在抽象类中封装了算法的主要步骤,并使用抽象方法和钩子方法来实现可变的部分。这种设计模式使得算法的结构保持稳定,而具体的实现细节可以由子类提供。

    模板方法设计模式的优势在于:

    1. 提高代码复用性:将共同的代码逻辑封装在抽象类中,可以在不同的子类中共享使用,避免了重复编写相似的代码。
    2. 简化子类实现:通过将算法中的可变部分定义为抽象方法,子类只需要关注自己特定的实现细节,从而简化了子类的实现。
    3. 提供扩展点:通过钩子方法,允许子类在特定的执行点插入自己的逻辑,以实现对算法的定制和扩展。

    然而,在使用模板方法设计模式时也需要考虑一些因素和注意事项:

    1. 需要明确模板方法的执行流程和步骤顺序,确保每个步骤的执行时机正确。
    2. 钩子方法应该有默认的空实现,以保证子类可以选择是否覆盖它。
    3. 合理使用钩子方法,不要过度使用,避免引入不必要的复杂性。
    4. 钩子方法的命名应该具有描述性,以便子类理解和正确使用。
  • 相关阅读:
    leetcode-92:反转链表 II
    前端控制小数点精度及数字千位分割
    Spring framework day 01:spring 整合数据源(连接池)
    【编程题】【Scratch二级】2019.09 绘制雪花图案
    《深入浅出图神经网络--GNN原理解析》一些概念【待整理完】
    乳糖不耐者的福音:这些常见乳制品的替代品快来了解一下吧!
    如果刷新网页或者下拉出现白屏可能是什么原因以及url相关问题
    【深度学习】图形模型基础(1):使用潜在变量模型进行数据分析的box循环
    JVM之【运行时数据区2——堆】
    【NPM】particles.vue3 + tsparticles 实现粒子效果
  • 原文地址:https://blog.csdn.net/pengjun_ge/article/details/132634812