行为模式-模板方法模式

发布于:2025-08-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

定义:

        Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.(定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改 变一个算法的结构即可重定义该算法的某些特定步骤。)

模板方法模式通用类图

        模板方法设计模式的核心思想是“定义算法骨架,将可变部分延迟到子类实现”。它将算法中不变的部分封装在抽象类的模板方法中,而将可变的部分抽象成抽象方法或钩子方法,由子类具体实现。这样可以避免代码重复,同时允许子类在不改变算法整体结构的情况下,对某些步骤进行定制化实现。

角色:

模板方法模式包含以下几个核心角色:

1、抽象类(Abstract Class)

        抽象类定义了一个模板方法,该方法包含了算法的骨架,具体步骤由一系列方法调用组成。这些方法可以是抽象方法、具体方法或钩子方法:

  1. 抽象方法:由抽象类声明,具体实现由子类完成。
  2. 具体方法:在抽象类中已经实现,子类可以直接使用或重写。
  3. 钩子方法:在抽象类中提供默认实现,子类可以选择重写或不重写。钩子方法通常用于控制算法的流程。

2、具体子类(Concrete Class)

        具体子类继承自抽象类,实现抽象类中的抽象方法,必要时重写钩子方法,以实现特定的业务逻辑。具体子类不改变算法的结构,只负责实现算法中的某些步骤。

代码示例:

        咖啡和茶的制作过程有相似的步骤:烧水、冲泡、倒入杯中、添加调料。使用模板方法设计模式实现这两种饮品的制作过程。

// 抽象类:饮品制作

public abstract class Beverage {

    // 模板方法:定义制作饮品的算法骨架

    public final void prepareRecipe() {

        boilWater();

        brew();

        pourInCup();

        if (customerWantsCondiments()) {

            addCondiments();

        }

    }



    // 具体方法:烧水

    protected final void boilWater() {

        System.out.println("烧开水");

    }

    // 抽象方法:冲泡

    protected abstract void brew();

    // 具体方法:倒入杯中

    protected final void pourInCup() {

        System.out.println("倒入杯中");

    }

    // 抽象方法:添加调料

    protected abstract void addCondiments();

    // 钩子方法:是否添加调料,默认添加

    protected boolean customerWantsCondiments() {

        return true;

    }

}

// 具体子类:咖啡

public class Coffee extends Beverage {

    @Override

    protected void brew() {

        System.out.println("冲泡咖啡粉");

    }



    @Override

    protected void addCondiments() {

        System.out.println("添加糖和牛奶");

    }

}

// 具体子类:茶

public class Tea extends Beverage {

    @Override

    protected void brew() {

        System.out.println("浸泡茶叶");

    }



    @Override

    protected void addCondiments() {

        System.out.println("添加柠檬");

    }



    // 重写钩子方法,自定义是否添加调料

    @Override

    protected boolean customerWantsCondiments() {

        // 模拟用户选择

        return Math.random() > 0.5;

    }

}

// 客户端代码

public class BeverageClient {

    public static void main(String[] args) {

        System.out.println("制作咖啡...");

        Beverage coffee = new Coffee();

        coffee.prepareRecipe();



        System.out.println("\n制作茶...");

        Beverage tea = new Tea();

        tea.prepareRecipe();

    }

}

优点 :

1.提高代码复用性:将通用的算法结构放在抽象类中,避免了在多个子类中重复实现相同的代码,提高了代码的复用性。

2.简化子类实现:子类只需实现抽象类中定义的抽象方法和需要重写的钩子方法,而不需要关心算法的整体结构,简化了子类的实现。

3.便于控制算法流程:模板方法模式将算法的控制权集中在抽象类中,子类只能在允许的范围内进行扩展,便于控制算法的流程和行为。

4.符合开闭原则:当需要修改或扩展算法的某些步骤时,只需创建新的子类,而不需要修改抽象类的代码,符合开闭原则。


缺点:

1.限制子类灵活性:模板方法模式通过继承实现代码复用,子类必须遵循抽象类定义的算法结构,可能会限制子类的灵活性。

2.增加类的数量:随着算法步骤的增加,抽象类和子类的数量可能会增多,导致系统的类层次结构变得复杂,增加了代码的理解和维护难度。

3.父类与子类耦合度较高:模板方法模式中,抽象类定义了算法的骨架,子类依赖于抽象类的实现。如果抽象类发生变化,可能会影响到所有的子类,导致父类与子类之间的耦合度较高。


使用场景:

(一)多个算法有相似结构的场景

        当多个算法或操作具有相似的结构,但某些步骤的实现方式不同时,可以使用模板方法设计模式。将通用的算法结构放在抽象类中,而将不同的步骤实现延迟到子类中,避免代码重复。

(二)需要控制子类扩展的场景

        模板方法模式允许在不改变算法整体结构的情况下,通过子类来扩展或修改算法的某些步骤。抽象类可以定义哪些步骤是必须实现的(抽象方法),哪些步骤是可以选择性实现的(钩子方法),从而控制子类的扩展方式。

(三)希望提高代码复用性的场景

        模板方法设计模式通过继承实现代码复用,将通用的代码放在抽象类中,而将特殊的代码放在子类中。这样可以减少代码冗余,提高代码的复用性和可维护性。

(四)框架设计场景

        在框架设计中,模板方法模式经常被用来定义框架的核心流程,而将一些具体的实现细节留给开发者。例如,Java 的 Servlet API 中,HttpServlet 类就使用了模板方法模式,定义了处理 HTTP 请求的基本流程,开发者只需重写 doGet()、doPost() 等方法即可。 

        模板方法设计模式通过定义算法的骨架,将可变部分延迟到子类实现,为软件开发提供了一种优雅的代码复用和扩展方式。它在多个领域都有广泛的应用,如游戏开发中的角色行为模式、软件开发中的框架设计等。合理运用模板方法设计模式,可以使代码更加简洁、灵活和易于维护。然而,在使用时也需要注意其缺点,避免过度使用导致类层次结构复杂。通过权衡利弊,我们可以在适当的场景下使用模板方法模式,发挥其最大的优势。


网站公告

今日签到

点亮在社区的每一天
去签到