• 【设计模式(22)】行为型模式之模板模式


    个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道

    如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充


    开发过程中,我们通常会遇到这样的情况:我们已经制定好了方案,并确定了相关执行步骤,但某些具体的步骤还未知,或者说具体的步骤与环境相关

    如,乘坐飞机、火车等交通工具出远门,都需要买票-验票进站-等车-上车-下车-出站等一套流程,但具体需要处理的细节却不完全一样,买票的渠道、验票进站的步骤、上下飞机/火车的方式等等,都不一样。

    那么,我们可以把这些规定了流程或格式的实例定义成模板,允许使用者根据自己的需求去更新它


    1.定义

    使用目的:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤

    使用时机:有一套相同的流程,但具体实现方案不一样

    解决问题:流程中的一些方法通用,却在每一个子类都重新写了这一方法。

    实现方法:流程在抽象类实现,步骤在子类实现。

    应用实例:

    • 乘坐飞机、火车、轮船等交通工具的流程,都需要买票-验票-候车-上车-下车-出站的流程
    • spring对事务的处理,如开启事务、获取 Session、关闭 Session 等
    • MVC模型

    优点

    • 封装不变部分,扩展可变部分。
    • 提取公共代码,便于维护。
    • 行为由父类控制,子类实现

    缺点

    • 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
    • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
    • 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。

    注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。


    2.结构

    模板模式包含以下角色:

    • 抽象类/抽象模板(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成
    • 具体子类/具体实现(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤

    模板方法模式的结构图


    3.步骤

    1. 构建抽象模板类

      //抽象类
      abstract class AbstractClass {
          //模板方法
          public void TemplateMethod() {
              SpecificMethod();
              abstractMethod1();
              abstractMethod2();
              abstractMethod3();
          }
      
          //具体方法
          public void SpecificMethod() {
              System.out.println("抽象类中的具体方法被调用...");
          }
      
          //抽象方法1
          public abstract void abstractMethod1();
      
          //抽象方法2
          public abstract void abstractMethod2();
      
          //抽象方法2
          public abstract void abstractMethod3();
      }
      
    2. 构建具体子类

      //具体子类A
      class ConcreteClassA extends AbstractClass {
          public void abstractMethod1() {
              System.out.println("模板A中的方法1被调用");
          }
      
          public void abstractMethod2() {
              System.out.println("模板A中的方法2被调用...");
          }
      
          @Override
          public void abstractMethod3() {
              System.out.println("模板A中的方法3被调用...");
          }
      }
      
      //具体子类B
      class ConcreteClassB extends AbstractClass {
          public void abstractMethod1() {
              System.out.println("模板B中的方法1被调用");
          }
      
          public void abstractMethod2() {
              System.out.println("模板B中的方法2被调用...");
          }
      
          @Override
          public void abstractMethod3() {
              System.out.println("模板B中的方法3被调用...");
          }
      }
      

    测试代码

    public class TemplateTest {
        public static void main(String[] args) {
            AbstractClass tmA = new ConcreteClassA();
            tmA.TemplateMethod();
            AbstractClass tmB = new ConcreteClassB();
            tmB.TemplateMethod();
        }
    }
    

    运行结果

    image-20210714182727065


    4.扩展

    模板模式由抽象模板规定了算法的骨架,即具体方法的执行顺序和逻辑

    那么,我们可以通过钩子方法,使不同的具体子类能够执行不同的具体方法


    具体代码

    package com.company.designPattern.template;
    
    public class TemplateHockTest {
        public static void main(String[] args) {
            AbstractHockClass tmA = new ConcreteHockClassA();
            tmA.TemplateMethod();
        }
    }
    
    //抽象类
    abstract class AbstractHockClass {
        //模板方法
        public void TemplateMethod() {
            SpecificMethod();
            // 执行钩子1和具体方法1
            hockMethod1();
            abstractMethod1();
            // 根据钩子2结果是否执行具体方法2
            if (hockMethod2()) {
                abstractMethod2();
            }
        }
    
        //具体方法
        public void SpecificMethod() {
            System.out.println("抽象类中的具体方法被调用...");
        }
    
        // 钩子方法1
        public void hockMethod1() {
            System.out.println("默认钩子方法1被调用");
        }
    
        //抽象方法1
        public abstract void abstractMethod1();
    
        // 钩子方法2
        public boolean hockMethod2() {
            System.out.println("默认钩子方法2被调用");
            return true;
        }
    
        //抽象方法2
        public abstract void abstractMethod2();
    }
    
    //具体子类A
    class ConcreteHockClassA extends AbstractHockClass {
        public void abstractMethod1() {
            System.out.println("模板A中的方法1被调用");
        }
    
        public void abstractMethod2() {
            System.out.println("模板A中的方法2被调用...");
        }
    
        @Override
        public boolean hockMethod2() {
            System.out.println("默认钩子方法2被调用");
            return false;
        }
    }
    

    通过钩子方法,我们达到下面效果

    • 执行通用具体方法
    • 通过钩子1对方法1进行预处理
    • 根据钩子2判断是否执行方法2

    执行结果

    image-20210720113910763


    后记

    模板方法的目的是将按照统一模板的方法进一步规范化,通过继承重写和模板方法来保证多个具体子类按照同样的算法执行

    说白点,量产化,将统一的方法通过父类的abstract方法控制,统一的流程通过父类中的模板方法设定,子类自行控制每个步骤的执行细节

    当然也可以根据实际需求进行变型,毕竟服务于实际开发才是设计模式的目的



    作者:Echo_Ye

    WX:Echo_YeZ

    Email :echo_yezi@qq.com

    个人站点:在搭了在搭了。。。(右键 - 新建文件夹)

  • 相关阅读:
    [转]Xml Schema
    设计模式之Observer Pattern
    通过 C# 使用 J# 类库中的 Zip 类压缩文件
    An extender can't be in a different UpdatePanel than the control it extends
    关于AutoResetEvent和ManualResetEvent
    ref, out参数区别
    取整, 无条件进位, 无条件取整
    VB.NET语法基础
    XP防火墙,挡掉访问自己的IIS
    maybe useful for Add the solution to source control
  • 原文地址:https://www.cnblogs.com/silent-bug/p/15034134.html
Copyright © 2020-2023  润新知