美文网首页
设计模式-模板方法模式

设计模式-模板方法模式

作者: 在中国喝Java | 来源:发表于2022-12-07 09:19 被阅读0次

模板方法模式(Template Method Pattern)又叫模板模式,是指定义一个操作中的算法的框 架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步 骤,属于行为型设计模式。

模板方法模式实际上是封装了一个固定流程,该流程由几个步骤组成,具体步骤可以由子类进行不 同实现,从而让固定的流程产生不同的结果。它非常简单,其实就是类的继承机制,但它却是一个应用 非常广泛的模式。模板方法模式的本质是抽象封装流程,具体进行实现。

模板模式UML类图

image.png

具体代码实现:

public abstract class AbstractTemplate {

    public abstract void step1();
    public abstract void step2();
    public abstract void step3();

    public abstract boolean hookMethod();

    public void templateMethod(){
        step1();
        step2();
        if(hookMethod()){
            step3();
        }
    }
}
复制代码
public class ConcreateTemplate extends AbstractTemplate{

    public void step1(){
        System.out.println("step1");
    }
    public void step2(){
        System.out.println("step2");
    }

    public void step3(){
        System.out.println("step3");
    }

    public boolean hookMethod(){
        return true;
    }
}
复制代码
public class Test {
    public static void main(String[] args) {
        ConcreateTemplate concreateTemplate = new ConcreateTemplate();
        concreateTemplate.templateMethod();
    }
}
复制代码

这里需要注意的是这个hookMethod钩子函数可有可无,设计钩子方法的主要目的是用来干预执行流程,使得我们控制行为流程更加灵活,更符合实际业务的需求。钩子方法的返回值一般为适合条件分支语句的返回值(如 boolean、 int等)。具体可以根据自己的业务场景来决定是否需要使用钩子方法。

示例代码

我们封装一下rocketmq发送下消息的流程,rocketmq的流程是比较固定的,大致分为三步,启动生产者、发送消息、关闭应用程序,我们可以吧这三步固定在抽象类中,让子类去实现:

抽象模板:

public abstract class RocketMQProducerTemplate {
    DefaultMQProducer producer;

    public RocketMQProducerTemplate(){
        this.producer = new DefaultMQProducer("tudou1");
        producer.setNamesrvAddr("127.0.0.1:9876");
    }
    public abstract void start();
    public abstract void send(String message);
    public void close(){
        producer.shutdown();
    }
    public void sendMessage(String message) {
        start();
        send(message);
        close();
    }
}
复制代码

实际实现:

public class ProducerA extends RocketMQProducerTemplate{

    @Override
    public void start() {
        try{
            producer.start();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void send(String message) {
        Message msg = new Message("test","TestA", message.getBytes());
        try{
            SendResult result = super.producer.send(msg);
        }catch(Exception e){
            e.printStackTrace();
        }

    }
}
复制代码

这里也可以将启动消费者的代码放到抽象类中,具体根据业务来,有的业务可能启动失败要走其他流程针对这种情况就需要放到子类中实现

源码中的体现

MyBatis源码中的BaseExecutor类就是一个模板类其中有update方法如下:

public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (this.closed) {
        throw new ExecutorException("Executor was closed.");
    } else {
        this.clearLocalCache();
        return this.doUpdate(ms, parameter);
    }
}
复制代码

发现在update方法里面调用了了doUpdate方法 [图片上传失败...(image-bf60e8-1670462340514)]

doUpdate方法就是一个抽象方法,主要让子类去实现 [图片上传失败...(image-ff290c-1670462340514)]

模板方法优缺点

优点:

  1. 利用模板方法将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
  2. 将不同的代码不同的子类中,通过对子类的扩展增加新的行为,提高代码的扩展性。
  3. 把不变的行为写在父类上,去除子类的重复代码,提供了一个很好的代码复用平台,符合开闭原则。

缺点:

  1. 类的个数增加,应为每种逻辑都需要新增一个实现类
  2. 系统复杂度增加
  3. 如果父类新增抽象方法,子类都需要实现一遍

作者

相关文章

网友评论

      本文标题:设计模式-模板方法模式

      本文链接:https://www.haomeiwen.com/subject/rulnfdtx.html