设计模式之模板方法模式

52 阅读3分钟

1. 模板方法模式

1.1 定义

模板模式(Template Method Pattern)是一种行为设计模式,它定义了一个操作中的算法骨架,但将一些步骤延迟到子类中实现。这种模式允许你定义一个算法的基础结构,并且可以由子类来重写某些特定步骤而不会改变算法的结构。模板模式的核心思想是封装变化的部分,提供扩展点,使得子类能够以不同的方式实现这些变化部分。

模板模式的关键组件

  1. 抽象类:定义了模板方法以及一系列基本操作方法。
    • 模板方法:定义了算法的骨架,通常是一个 final 方法,防止子类覆盖。
    • 基本操作:这些方法可以是抽象的,也可以有默认实现,供子类选择性地覆盖。
    • 钩子方法:提供一种方式让子类对算法的某个步骤进行控制或修改。它们通常是空操作或者具有默认行为的方法。
  2. 具体类:继承自抽象类,实现或重写基本操作和/或钩子方法,从而定制算法的具体细节。

1.2 使用场景

  • 当你的多个类有相似的行为,只有少数步骤不同。
  • 当你想为通用算法提供一个框架,同时允许子类自定义算法的某些步骤。
  • 当你需要在不改变算法结构的情况下,支持多种不同的执行方式。

1.3 优点

  • 封装了不变部分的代码,提高了代码复用性。
  • 提高了代码的可维护性,因为公共部分的更改只需要在父类中进行。
  • 通过将相同的代码移动到超类,减少了代码重复。

1.4 缺点

  • 每个不同的实现都需要一个新的子类,这可能会导致系统中类的数量增加。
  • 如果父类添加新的抽象方法,所有子类可能需要相应地更新,这可能导致大量的代码改动。

1.5 代码示例

①定义抽象类

public abstract class DataViewer {

    /**
     * 抽象方法:获取数据
     */
    public abstract void GetData();

    /**
     * 具体方法:转换数据
     */
    public void ConvertData() {
        System.out.println("将数据转换为XML格式。");
    }

    /**
     * 抽象方法:显示数据
     */
    public abstract String DisplayData();

    /**
     * 钩子方法:判断是否为XML格式的数据
     *
     * @return
     */
    public boolean IsNotXMLData() {
        return true;
    }

    /**
     * 模板方法
     */
    public String Process() {
        GetData();
        //如果不是XML格式的数据则进行数据转换
        if (IsNotXMLData()) {
            ConvertData();
        }
        return DisplayData();
    }
}

②具体子类实现

public class CsvDataViewer extends DataViewer{

    @Override
    public void GetData() {
        System.out.println("get csv data");
    }

    @Override
    public String DisplayData() {
        System.out.println("display csv data");
        return "csv";
    }

    @Override
    public void ConvertData() {
        System.out.println("将数据转换为csv格式。");
    }

    @Override
    public String Process() {
        GetData();
        //如果不是XML格式的数据则进行数据转换
        if (IsNotXMLData()) {
            ConvertData();
        }
        return DisplayData();
    }
    
}
public class XMLDataViewer extends DataViewer{
    @Override
    public void GetData() {
        System.out.println("get xml data");
    }

    @Override
    public String DisplayData() {
        System.out.println("display xml data");
        return "xml";
    }


    @Override
    public  boolean IsNotXMLData() {
        return false;
    }

}

③client调用

public class Client {

    public static void main(String[] args) {
        DataViewer dv;
        //dv = new XMLDataViewer();
        dv = new CsvDataViewer();
        System.out.println(dv.Process());
    }
}