Skip to content
CodingDiary
返回

设计模式之行为型设计模式-模板方法模式

导读

JdbcTemplate、RedisTemplate、MongoTemplate……Spring 为啥这么爱用 Template?因为模板方法模式太香了!本文用「短信/邮件发送器」的场景讲解:父类定义 validate → execute → error 的流程骨架,子类只需实现具体步骤。公共逻辑不重复,扩展新渠道只加子类。

1. 模式简介

定义一个程序的整体流程,并允许子类为其中的一个或者多个步骤提供具体实现。模板方法使得子类可以在不改变整体流程的情况下,重新定义其中的某些步骤。属于行为型设计模式

2. 示例代码

这里我们通过模板方法模式实现一个短信发送、邮件发送的 demo。

  • 定义一个整体流程
/**
 * <p>
 * 消息发送器
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/11/18 17:22
 */
public abstract class BaseMessageSender {
    /**
     * 发送消息
     *
     * @param content 内容
     */
    public void send(String content) {
        validate(content);
        if (!execute(content)) {
            error(content);
        }
    }

    /**
     * 校验消息
     *
     * @param content 数据
     */
    protected abstract void validate(String content);

    /**
     * 发送消息
     *
     * @param content 数据
     * @return {@code true} - 发送成功,{@code false} - 发送失败
     */
    protected abstract boolean execute(String content);

    /**
     * 错误记录
     *
     * @param content 数据
     */
    protected abstract void error(String content);
}
  • 短信发送的具体实现
/**
 * <p>
 * 短信发送器
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/11/18 17:40
 */
public class SmsSender extends BaseMessageSender {
    /**
     * 校验消息
     *
     * @param content 数据
     */
    @Override
    protected void validate(String content) {
        if (content == null || "".equals(content.trim()) || content.trim().length() != 11) {
            throw new RuntimeException("手机号码不合法");
        }
    }

    /**
     * 发送消息
     *
     * @param content 数据
     * @return {@code true} - 发送成功,{@code false} - 发送失败
     */
    @Override
    protected boolean execute(String content) {
        Random random = new Random();
        if (random.nextInt(10) % 2 == 0) {
            System.out.println("短信发送成功!");
            return true;
        } else {
            return false;
        }
    }

    /**
     * 错误记录
     *
     * @param content 数据
     */
    @Override
    protected void error(String content) {
        System.err.println("短信发送失败!手机号:" + content);
    }
}
  • 邮件发送的具体实现
/**
 * <p>
 * 邮件发送器
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/11/18 17:34
 */
public class EmailSender extends BaseMessageSender {
    /**
     * 校验消息
     *
     * @param content 数据
     */
    @Override
    protected void validate(String content) {
        if (content == null || "".equals(content.trim())) {
            throw new RuntimeException("数据不能为空");
        }
    }

    /**
     * 发送消息
     *
     * @param content 数据
     * @return {@code true} - 发送成功,{@code false} - 发送失败
     */
    @Override
    protected boolean execute(String content) {
        Random random = new Random();
        if (random.nextInt(10) % 2 == 0) {
            System.out.println("邮件发送成功!");
            return true;
        } else {
            return false;
        }
    }

    /**
     * 错误记录
     *
     * @param content 数据
     */
    @Override
    protected void error(String content) {
        System.err.println("邮件发送失败!发送内容:" + content);
    }
}
  • 测试类
/**
 * <p>
 * 模板模式,测试类
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/11/18 17:10
 */
public class PatternTest {
    public static void main(String[] args) {
        // 邮件发送
        EmailSender emailSender = new EmailSender();
        emailSender.send("测试内容");

        // 短信发送
        SmsSender smsSender = new SmsSender();
        smsSender.send("17312341234");
    }
}
  • 测试结果
邮件发送失败!发送内容:测试内容
短信发送成功!

3. UML 图例

design-pattern-template-uml

4. 应用

// Spring Data 这个模块下存在特别多的应用
// 比如:
// JdbcTemplate、RedisTemplate、MongoTemplate、ElasticsearchTemplate

5. 场景

  • 一次性实现一个算法的主体流程的部分,并将可变的行为留给子类来实现。

  • 各子类中公共的行为被提取出来并集中到一个公共的父类中,从而避免代码重复。

6. 优缺点

优点: 1、提高代码的复用性。2、提高代码的扩展性。3、符合开闭原则。

缺点: 1、导致类的数目增加。2、间接地增加了系统实现的复杂度。3、继承关系存在自身缺点,如果父类添加了新的抽象方法,所有子类都需要重新改一遍。

7. 完整代码地址

https://github.com/xkcoding/design-pattern/tree/master/src/main/java/com/xkcoding/design/pattern/behavioral/template


CC BY-NC-SA 4.0

本文采用 CC BY-NC-SA 4.0 协议,转载请注明出处。

原文链接: https://xkcoding.com/2019-10-16-design-pattern-template.html