模板方法模式

基本定义

所谓模板方法模式就是在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤

简单来说就是,抽象类提供一组算法和部分逻辑的实现,具体子类实现剩余逻辑

模式结构

在这里插入图片描述

  • AbstractClass: 抽象类
    • 定义一个或者多个抽象操作,以便让子类实现
    • 定义并实现一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能有一些具体方法
    • 抽象类剋有任意多个模板方法,而不限于一个。每个模板方法都可以调用任意多个具体方法,一般模板方法都用final修饰,子类不允许修改整套逻辑
  • ConcreteClass: 具体子类
    • 实现父类模板方法中调用的,交由子类实现的抽象方法,父类一般用abstract修改这些抽象方法

这里讲一下基本方法:

  • 抽象方法:一个抽象方法由抽象类声明,由具体子类实现,方法使用abstract关键字修饰

  • 具体方法:一个具体方法由抽象类声明并实现。一个具体方法没有abstract关键字

  • 钩子方法:一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空的实现,作为方法的默认实现

    • 抽象类有多个模板方法的时候

      public abstract class Parent{
          
          final templateMethod1(){
              
              method1();
              
              method2();  
          }
          
          final templateMethod2(){
              
          }
          
          abstract void method1();
          abstract void method2();
          abstract void method3();
      }
      

      假设子类A 关注模板1-> method1, 子类B关注模板2 -> method2, method3

      假设不提供空实现,子类A不止要实现自己的method1, 还得实现method2,method3, 当Parent方法一多或者子类很多,那每个类是不是很乱(包含自己不需要实现的方法)

      public class ChildrenOne extends Parent {
          
          @Override
          void method1() {
              
          }
      
          // 不需要的method2, 3
          @Override
          void method2() {
      
          }
      
          @Override
          void method3() {
      		
          }
      }
      
    • 父类提供空实现

      public abstract class Parent {
          
          final void templateMethod1(){
              
              method1();
              
              method2();
              
          }
      
          final void templateMethod2(){
              method3();
          }
          
          void method1(){}
      
          void method2(){};
          
          void method3(){};
      }
      
      public class ChildrenOne extends Parent {
         
          @Override
          void method1() {
              
          }
      
      }
      

模板实现

模拟读取不同文件格式,然后输出读取内容的场景,每个处理包括严重文件、解析文件数据、展示数据内容的通用步骤

  • 定义抽象类 AbstractHandler

    public abstract class AbstractHandler {
    
    
        public final void process(String filepath) {
    
            begin();
            validate(filepath);
            parseData(filepath);
            display(filepath);
            end();
        }
    
        abstract void validate(String filepath);
    
        abstract void parseData(String filepath);
    
        abstract void display(String filepath);
    
        // 钩子方法
        public void hookMethod() {
    
        }
    
        public void concreteMethod() {
    
        }
    
        public void begin() {
            System.out.println("begin");
        }
    
        public void end() {
            System.out.println("end");
        }
    
    }
    
  • 然后定义子类去实现抽象方法即可:csv、pdf、excel

源码使用

  • InputStream: 复用

    // read函数是一个模板方法,定义了读取数据的整个流程,并暴露了一个可以由于子类来定制的抽象方法
    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }
    
        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;
    
        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }
    
    // 抽象方法交给子类实现
    public abstract int read() throws IOException;
    
    public class ByteArrayInputStream extends InputStream {
        public synchronized int read() {
            return (pos < count) ? (buf[pos++] & 0xff) : -1;
        }
    }
    
  • Java AbstractList: 复用

    // allAll(),add(E e)函数其实可以看作是模板方法,add()是子类需要重写的方法,尽管是没有声明abstract,但是函数直接异常,子类不重写是不能使用的
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }
    
    public boolean add(E e) {
        add(size(), e);
        return true;
    }
    
    
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }
    
    
  • Java Servlet: 扩展, 让我们客户端自己去实现抽象方法,而不是框架自带

    • 经常的我们使用,定义一个类然后继承HttpServlet, 其实doGet和doPost就是类似子类实现抽象方法

      public class HelloServlet extends HttpServlet{
          
          doGet(){
              //......
          }
          
          doPost(){
              // .....
          }
      }
      
    • 来看一下HttpServlet的service, Servlet都是走service方法

      // service其实就是一个模板方法,实现了整个HTTP的请求流程,DoGet和doPost是模板红可以由子类来定制的部分。实际上,这就相当于Servlet提供一个扩展点(DoGet和doPost).让框架用户在不用修改Servlet框架源码的情况下,将业务代码通过扩展点镶嵌到框架中执行
      public void service(ServletRequest req, ServletREsponse res){
          HttpServletRequest request= (HttpServletRequest)req
          String method = request.getMethod
          if(method.equals(METHOD_GET)){
      		doGet();
          }
          if(method.equals(METHOD_POST)){
      		doPost();
          }
          //.............
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值