设计模式轻松学【十三】模版方法模式

简介: 我们去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。

在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。

模式定义与特点

  • 定义

    声明一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。它是一种类行为型模式。

  • 参与角色

    • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。

      1. 模板方法:抽象类声明并实现,一般是定义算法的骨架,按某种顺序调用其包含的基本方法。并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
      2. 基本方法:是整个算法中的一个步骤,包含以下几种类型。

        • 抽象方法(abstractMethod):在抽象类中申明,可定义多个,由具体子类实现。
        • 具体方法(concreteMethod):抽象类中声明并实现,一般不建议子类实现
        • 钩子方法(hookMethod):抽象类中声明并给出空实现,子类可以选择性的进行扩展实现。
    • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
  • 类结构图

    image.png

  • 结构代码实现

    • 抽象模板

      abstract class AbstractTemplate {
          //1个模板方法,用于规定具体模板执行的步骤
          public void templateMethod() {
              //具体的方法调用可以调整,就好比先吃菜还是先吃饭,二者都可以
              abstractMethod();
              concreteMethod();
              hookMethod();
          }
          
          //多个基本方法
          //包括1...n个抽象,1个具体,1个钩子方法
          public abstract void abstractMethod();
          
          //具体方法,抽象类中声明并实现,不建议子类实现,一般设计成私有的
          private void concreteMethod() {
              System.out.println("父类具体的方法");
          }
          
          //钩子方法,抽象类中声明并给出空实现,子类可以选择性的实现
          public void hookMethod() {
              
          }
      }
    • 具体模板

      class ConcreteTemplate1 extends AbstractTemplate{
      
          @Override
          public void abstractMethod() {
              System.out.println("这是子类1的具体实现");
          }
      }
      
      class ConcreteTemplate2 extends AbstractTemplate {
      
          @Override
          public void abstractMethod() {
              System.out.println("这是子类2的具体实现");
          }
      }
    • 客户端调用程序

      public class TemplateMethodTest {
      
          public static void main(String[] args) {
              //使用第一个模板
              AbstractTemplate concreteTemplate1 = new ConcreteTemplate1();
              concreteTemplate1.templateMethod();
              //使用第二个模板方法
              AbstractTemplate concreteTemplate2 = new ConcreteTemplate2();
              concreteTemplate2.templateMethod();
          }
      }

模式实现分析

现在我们来实现去银行办理业务的案例,办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分。除了办理具体业务不一样外,其他的流程一样,我们可以进行如下编程。

  • 声明抽象类

    abstract class AbstractBankHandler {
        //准备去办理业务
        public void prepareHandler() {
            //具体的方法调用可以调整,就好比先吃菜还是先吃饭,二者都可以
            getNumber();
            lineUp();
            handler();
            evaluate();
            hookMethod();
        }
        
        //多个基本方法
        //取号是一样的,所以直接实现,直接实现的方法建议声明为private
        private void getNumber() {
            System.out.println("取号");
        }
        //排队,一样的,所以直接实现
        private void lineUp() {
            System.out.println("慢慢长路在排队");
        }
        //办理业务,不一样,子类实现
        public abstract void handler();
        
        //评价,不一样,每个人的评价不一样
        public abstract void evaluate();
        
        //钩子方法,抽象类中声明并给出空实现,子类可以选择性的实现
        public void hookMethod() {
            
        }
    }
  • 声明具体类

    class PersonA extends AbstractBankHandler{
        @Override
        public void handler() {
            System.out.println("存200万");
        }
        @Override
        public void evaluate() {
            System.out.println("五星好评");
        }
    }
    
    class PersonB extends AbstractBankHandler {
    
        @Override
        public void handler() {
            System.out.println("取1000万");
        }
    
        @Override
        public void evaluate() {
            System.out.println("态度不好,差评");
        }
    }
  • 客户端调用

    public class TemplateMethodTest {
    
        public static void main(String[] args) {
            //使用第一个模板
            AbstractBankHandler personA = new PersonA();
            personA.prepareHandler();
            
            //使用第二个模板方法
            AbstractBankHandler personB = new PersonB();
            personB.prepareHandler();
        }
    }

通过上面程序,我们知道,对于流程相同,子类实现不同的操作我们可以采用模板方法模式来实现,这大大的提高了我们代码的复用率。

总结

  • 优点

    • 提高代码复用性,将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中
    • 实现了反向控制, 比较灵活。因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。
  • 缺点

    • 引入了抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,从而增加了系统实现的复杂度。
  • 应用场景

    • 在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。
目录
相关文章
|
2月前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
137 11
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
24天前
|
设计模式
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
86 40
|
25天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——简单工厂模式
简单工厂模式是一种创建型设计模式,通过工厂类根据传入参数创建不同类型的对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。适用于对象种类较少且调用者无需关心创建细节的场景。
53 19
|
23天前
|
设计模式 Java
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
50 12
|
25天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——工厂方法模式
简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入参数创建不同类型的产品对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。适用于创建对象种类较少且调用者无需关心创建细节的场景。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。
44 15
|
3月前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
3月前
|
设计模式 安全 Java
Kotlin - 改良设计模式 - 构建者模式
Kotlin - 改良设计模式 - 构建者模式
|
3月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
63 1
|
4月前
|
设计模式 Java Kotlin
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin语法,推荐查看“简洁”系列教程。本文重点介绍了构建者模式在Kotlin中的应用与改良,包括如何使用具名可选参数简化复杂对象的创建过程,以及如何在初始化代码块中对参数进行约束和校验。
46 3

热门文章

最新文章