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

简介: 我们去银行办理业务一般要经过以下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();
        }
    }

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

总结

  • 优点

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

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

    • 在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。
目录
相关文章
|
1天前
|
设计模式
设计模式-单一职责模式
设计模式-单一职责模式
|
1天前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
1天前
|
设计模式 XML Java
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
文章详细介绍了简单工厂模式(Simple Factory Pattern),这是一种创建型设计模式,用于根据输入参数的不同返回不同类的实例,而客户端不需要知道具体类名。文章通过图表类的实例,展示了简单工厂模式的结构、时序图、代码实现、优缺点以及适用环境,并提供了Java代码示例和扩展应用,如通过配置文件读取参数来实现对象的创建。
【一】设计模式~~~创建型模式~~~简单工厂模式(Java)
|
5天前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。
设计模式-------------工厂模式之工厂方法模式(创建型)
|
5天前
|
设计模式 uml C语言
设计模式----------工厂模式之简单工厂模式(创建型)
这篇文章详细介绍了简单工厂模式,包括其定义、应用场景、UML类图、通用代码实现、运行结果、实际应用例子,以及如何通过反射机制实现对象创建,从而提高代码的扩展性和维护性。
设计模式----------工厂模式之简单工厂模式(创建型)
|
6天前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。
|
6天前
|
设计模式 uml C语言
设计模式----------工厂模式之简单工厂模式(创建型)
这篇文章详细介绍了简单工厂模式,包括其定义、应用场景、UML类图、通用代码实现、运行结果、实际应用例子,以及如何通过反射机制实现对象创建,从而提高代码的扩展性和维护性。
设计模式----------工厂模式之简单工厂模式(创建型)
|
5天前
|
设计模式 人工智能 达摩院
设计模式的基础问题之模板模式在软件开发中的优势是什么
设计模式的基础问题之模板模式在软件开发中的优势是什么
|
5天前
|
设计模式 项目管理
设计模式的基础问题之生成器模式在项目管理应用的问题如何解决
设计模式的基础问题之生成器模式在项目管理应用的问题如何解决
|
6天前
|
设计模式 Java API
设计模式-------------静态/动态代理模式(结构型设计模式)
本文详细介绍了代理模式,包括其定义、应用场景、UML类图、代码实现和实际例子,阐述了静态代理和动态代理的区别以及它们的优缺点,展示了如何通过代理模式来控制对目标对象的访问并增强其功能。