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


编辑页面
分享到:

上一篇
设计模式之行为型设计模式-观察者模式
下一篇
Easy Mock 基本用法