zoukankan      html  css  js  c++  java
  • Java设计模式之模板模式

    概论

    什么是模板模式呢?模板模式是这么定义的:定义一个操作中的算法的框架,而将这个框架中的某一些步骤延迟到子类中。使得子类可以不改变一个算法的结构。而能够重新定义该算法的某一些特定的步骤。

    模板模式示例

    举个例子,假如我们工作中的系统需要和许多的外部系统做交互时。由于外部系统各种各样,因此我们在发起请求时,处理方式会有所不多,有些是http请求,有些的webservice请求。或者是其他请求。然而真正在做的应该分成4个步骤。

    1.参数校验。

    2.封装对外的请求参数。

    3.对外提交请求。

    4.后置处理,例如记录操作日志。

    ok,首先我们需要拥有一个抽象模板类用来定义这些步骤。

     1 package com.example.pattern.template;
     2 
     3 public abstract class AbstractProccessor {
     4 
     5     public boolean validate(ExampleContext context) {
     6         if (context == null) {
     7             return false;
     8         }
     9 
    10         return true;
    11     }
    12 
    13     public abstract void prepare(ExampleContext context);
    14 
    15     public abstract void proccess(ExampleContext context);
    16 
    17     public abstract void after(ExampleContext context);
    18 
    19 
    20     
    21     public void run (ExampleContext context) {
    22 
    23         validate(context);
    24 
    25         prepare(context);
    26 
    27         proccess(context);
    28 
    29         after(context);
    30 
    31     }
    32 
    33 }

     抽象模板类AbstractProccessor 对外提供一个算法,也就是run方法。 这个算法中包含了参数校验,前置处理,提交请求,后置处理4个步骤。由于参数校验是最基本也是最公共的校验,因此在这个抽象模板中直接实现参数校验的具体方法。其他三个方法就以抽象方法的形态存在。

    现在我们新增一个具体的模板类。比如我们就叫HttpProccessor。

     1 package com.example.pattern.template;
     2 
     3 public class HttpProccessor extends AbstractProccessor {
     4 
     5     @Override
     6     public void prepare(ExampleContext context) {
     7 
     8         System.out.println("http 前置处理");
     9 
    10     }
    11 
    12     @Override
    13     public void proccess(ExampleContext context) {
    14 
    15         System.out.println("http 提交请求");
    16 
    17     }
    18 
    19     @Override
    20     public void after(ExampleContext context) {
    21         
    22         System.out.println("http 后置处理");
    23 
    24     }
    25 }

    我们继续新增一个模板类,命名为OtherProccessor。

     1 package com.example.pattern.template;
     2 
     3 public class OtherProccessor extends AbstractProccessor {
     4 
     5     @Override
     6     public void prepare(ExampleContext context) {
     7 
     8         System.out.println("other 前置处理");
     9 
    10     }
    11 
    12     @Override
    13     public void proccess(ExampleContext context) {
    14 
    15         System.out.println("other 提交请求");
    16 
    17     }
    18 
    19     @Override
    20     public void after(ExampleContext context) {
    21 
    22         System.out.println("other 后置处理");
    23 
    24     }
    25 }

    最后我们提供一个业务场景类Client

    package com.example.pattern.template;
    
    public class Client {
    
        public static void main(String[] args) {
            
            AbstractProccessor proccessor = new HttpProccessor();
    
            proccessor.run(new ExampleContext());
            
            
        }
    }

    执行结果如下所示:

    1 http 前置处理
    2 http 提交请求
    3 http 后置处理

    模板方法的精髓在于定义一个算法,这个算法中包含一系列的步骤,这些步骤如果是公共的步骤,可以提取在抽象模板类中实现,如果是模板个性化的行为,可以延迟到子类去实现。 

    现在再提出一个问题。我想在有些模板中不使用后置处理,有些模板中使用后置处理,也就是要不要后置处理,交给业务场景来确定,那该怎么办呢?我们在抽象模板类中增加一个方法标记是否需要后置处理。

     1 package com.example.pattern.template;
     2 
     3 public abstract class AbstractProccessor {
     4 
     5     public boolean validate(ExampleContext context) {
     6         if (context == null) {
     7             return false;
     8         }
     9 
    10         return true;
    11     }
    12 
    13     public abstract void prepare(ExampleContext context);
    14 
    15     public abstract void proccess(ExampleContext context);
    16 
    17     public abstract void after(ExampleContext context);
    18 
    19     protected boolean needAfterProccessing () {
    20         return true;
    21     }
    22 
    23 
    24 
    25     public void run (ExampleContext context) {
    26 
    27         validate(context);
    28 
    29         prepare(context);
    30 
    31         proccess(context);
    32 
    33         if(needAfterProccessing()) {
    34             after(context);
    35         }
    36     }
    37 
    38 }

     needAfterProccessing方法子类可以实现重写。代码如下所示:

     1 package com.example.pattern.template;
     2 
     3 public class HttpProccessor extends AbstractProccessor {
     4 
     5     protected boolean needAfterProccessing = false;
     6 
     7     @Override
     8     public void prepare(ExampleContext context) {
     9 
    10         System.out.println("http 前置处理");
    11 
    12     }
    13 
    14     @Override
    15     public void proccess(ExampleContext context) {
    16 
    17         System.out.println("http 提交请求");
    18 
    19     }
    20 
    21     @Override
    22     public void after(ExampleContext context) {
    23 
    24         System.out.println("http 后置处理");
    25 
    26     }
    27 
    28 
    29     @Override
    30     protected boolean needAfterProccessing() {
    31         return needAfterProccessing;
    32     }
    33 
    34 
    35     public boolean isNeedAfterProccessing() {
    36         return needAfterProccessing;
    37     }
    38 
    39     public void setNeedAfterProccessing(boolean needAfterProccessing) {
    40         this.needAfterProccessing = needAfterProccessing;
    41     }
    42 }

     我们再来修改一下客户端,设置不需要进行后置处理:

     1 package com.example.pattern.template;
     2 
     3 public class Client {
     4 
     5     public static void main(String[] args) {
     6 
     7         AbstractProccessor proccessor = new HttpProccessor();
     8 
     9         ((HttpProccessor) proccessor).setNeedAfterProccessing(false);
    10 
    11         proccessor.run(new ExampleContext());
    12 
    13 
    14     }
    15 }

    运行结果如下所示:

    1 http 前置处理
    2 http 提交请求

    通过以上的方式,我们采用把相同的代码(都要进行判断是不是需要后置处理)这个判断的抽象动作封装在抽象类中,而在子类再去约束他具体的行为,这个函数就叫作钩子函数

    模板模式的优点

    1.封装不变部分,扩展可变部分。

    2.提取公共部分。

    3.引入了钩子函数,行为由父类控制,子类实现。

    模板模式的缺点

    抽象类在一般情况下的作用是用来定义抽象行为,而模板模式却是将算法的处理步骤实现在抽象类中,抽象类中定义了抽象方法,交给子类去实现,而子类的实现方式会影响到父类的算法。在代码阅读上对技术有一定的要求。

    模板模式的使用场景

    1.多个子类有共有的方法,同时基本的处理逻辑相同。

    2.重要复杂的算法,可以把算法设计成模板模式,算法中的变化的步骤定义为抽象步骤。

    3.重构时,把相同或者相似的代码提取到抽象类中,并且使用钩子函数来约束父类的算法。

    一般对于Java的开发者而言,对HttpServlet都很熟悉。Servlet使用来浏览器和tomcat服务器沟通的桥梁,而这个桥梁的简单封装就是HttpServlet。每一次的请求都会去调用service方法,而service方法中根据请求的参数,调用不同的方法。例如doGet或者doPost。而doGet或者doPost都是在子类中定义定位,因此这两个函数也叫作钩子函数,即子类改变父类的行为。这也是对设计模式,模板模式的最佳应用。

  • 相关阅读:
    游戏与必胜策略
    中国剩余定理
    中国剩余定理
    欧几里得和扩展欧几里得
    欧几里得和扩展欧几里得
    51nod 1028 大数乘法 V2
    51nod 1028 大数乘法 V2
    51nod 1029 大数除法
    51nod 1029 大数除法
    51nod 1166 大数开平方
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/10026867.html
Copyright © 2011-2022 走看看