模板模式的引进

【第一版】中国人民银行发送短信例子,抽象发送的内容,发送短信的思路一致,内容不一样。

  1. 抽象短信发送模板

public abstract class AbstractSms {public void sendSms() {// 模拟参数传入Map context = new HashMap<>();context.put("name", "张三");context.put("money", 100);System.out.println("会话设置成功...");// 设置发送短信内容String fillSms = fillSms(context);// 发送短信,这里直接输出System.out.println("==》发送短信:" + fillSms);}/*** 填充短信内容*/protected abstract String fillSms(Map context);
}
  1. 存钱模板
/*** * Created by it* Created in 2019年4月13日* Description: 存钱*/
public class AddSms extends AbstractSms{@Overrideprotected String fillSms(Map context) {String message = "{NAME}在{TIME},存钱{MONEY}。【中国人民银行】";Map<String, Object> map = new HashMap<>();map.put("NAME", context.get("name"));map.put("TIME", "2019.4.13");map.put("MONEY", context.get("money"));String tagerStr = PlaceHolderReplaceUtils.replaceWithMap(message, map);return tagerStr;}}
  1. 取钱模板
/*** * Created by it* Created in 2019年4月13日* Description: 取钱*/
public class SubSms extends AbstractSms{@Overrideprotected String fillSms(Map context) {String message = "{NAME}在{TIME},取钱{MONEY}。【中国人民银行】";Map<String, Object> map = new HashMap<>();map.put("NAME", context.get("name"));map.put("TIME", "2019.4.13");map.put("MONEY", context.get("money"));String tagerStr = PlaceHolderReplaceUtils.replaceWithMap(message, map);return tagerStr;}
}
  1. 编写替换工具类,占位符替换
/*** Desc: 占位符替换, 占位符表示为:{@code {placeholder}};* <p>* 示例:替换如下{xxx}占位符中的内容* * <pre>* "名字:{name},年龄:{age},学校:{school}"* </pre>*/
public class PlaceHolderReplaceUtils {private static final Pattern pattern = Pattern.compile("\\{(.*?)\\}");private static Matcher matcher;/*** 替换字符串占位符, 字符串中使用{key}表示占位符** @param sourceString*            需要匹配的字符串,示例:"名字:{name},年龄:{age},学校:{school}";* @param param*            参数集,Map类型* @return*/public static String replaceWithMap(String sourceString, Map<String, Object> param) {if (isNullOrEmptyString(sourceString) || isEmptyMap(param)) {return sourceString;}String targetString = sourceString;matcher = pattern.matcher(sourceString);while (matcher.find()) {try {String key = matcher.group();String keyclone = key.substring(1, key.length() - 1).trim();Object value = param.get(keyclone);if (value != null) {targetString = targetString.replace(key, value.toString());}} catch (Exception e) {throw new RuntimeException("String formatter failed", e);}}return targetString;}private static boolean isEmptyMap(Map<String, Object> param) {if (param == null || param.isEmpty()) {return true;}return false;}private static boolean isNullOrEmptyString(String sourceString) {if (sourceString == null || "".equals(sourceString)) {return true;}return false;}
}
  1. 测试
public class TestSms {public static void main(String[] args) {AbstractSms sms = new AddSms();sms.sendSms();}
}

测试成功

当前问题

  1. 发送短信模板,替换内容及用户代码耦合性较高,需要拆分
  2. 是否需要短信提醒设置有缺陷,可能有的用户不需要提醒

细化模板模式,对上一问题改进

【第二版】中国人民银行发送短信例子,细化抽象短信

  1. 抽象短信发送模板

public abstract class AbstractSms {public void sendSms() {// 模拟参数传入Map context = new HashMap<>();context.put("name", "张三");context.put("money", 100);System.out.println("会话设置成功...");// 判断是否发送短信, 使用卫语句,校验层次if (!isSendSms(context)) {System.out.println("当前用户取消发送短信");return;}// 获取短信模板String smsTemplate = smsTemplate(context);// 获取参数替换Map smsParam = smsParam(context);// 最终短信String tagerStr = PlaceHolderReplaceUtils.replaceWithMap(smsTemplate, smsParam);// 发送短信,这里直接输出System.out.println("==》发送短信:" + tagerStr);}/*** 短信模板*/protected abstract String smsTemplate(Map context);/*** 参数替换*/protected abstract Map smsParam(Map context);/*** 是否发送短信*/protected abstract boolean isSendSms(Map context);
}
  1. 存钱模板
/*** * Created by it* Created in 2019年4月13日* Description: 存钱*/
public class AddSms extends AbstractSms{@Overrideprotected String smsTemplate(Map context) {String message = "{NAME}在{TIME},存钱{MONEY}。【中国人民银行】";return message;}@Overrideprotected Map smsParam(Map context) {Map<String, Object> map = new HashMap<>();map.put("NAME", context.get("name"));map.put("TIME", "2019.4.13");map.put("MONEY", context.get("money"));return map;}@Overrideprotected boolean isSendSms(Map context) {return true;}}
  1. 取钱模板
/*** * Created by it* Created in 2019年4月13日* Description: 取钱*/
public class SubSms extends AbstractSms{@Overrideprotected String smsTemplate(Map context) {String message = "{NAME}在{TIME},取钱{MONEY}。【中国人民银行】";return message;}@Overrideprotected Map smsParam(Map context) {Map<String, Object> map = new HashMap<>();map.put("NAME", context.get("name"));map.put("TIME", "2019.4.13");map.put("MONEY", context.get("money"));return map;}@Overrideprotected boolean isSendSms(Map context) {// 张三取消发送短信if ("张三".equals(context.get("name"))) {return false;}return true;}}
  1. 测试
public class TestSms {public static void main(String[] args) {AbstractSms sms = new AddSms();sms.sendSms();sms = new SubSms();sms.sendSms();}
}

测试成功

基本架构已经成功,也能满足我们后期扩展的需求,但是还是会有以下问题

  1. sendSms方法中,有与发送短信无关的功能
  2. 当前模板抽象方法众多,出现类似家族
  3. 后期扩展新的抽象方法AbstractSms的子类,现有实现,如AddSms的实现,代码如何复用,这里可能稍微难理解,也就是类AddSms的三个实现,我想复用在其他AbstractSms的子类,但是我不通过代码拷贝
  4. 如何要继续抽象新的想法,现有的AbstractSms子类如何对新增抽象方法不产生影响

桥连模式的引入

  1. 抽象原短信内容方法为统一接口
public interface SmsDefine {/*** 短信模板*/String smsTemplate(Map context);/*** 参数替换*/Map smsParam(Map context);/*** 是否发送短信*/boolean isSendSms(Map context);
}
  1. 修改原短信内容继承,存钱
/*** * Created by it* Created in 2019年4月13日* Description: 存钱*/
public class AddSms implements SmsDefine{@Overridepublic String smsTemplate(Map context) {String message = "{NAME}在{TIME},存钱{MONEY}。【中国人民银行】";return message;}@Overridepublic Map smsParam(Map context) {Map<String, Object> map = new HashMap<>();map.put("NAME", context.get("name"));map.put("TIME", "2019.4.13");map.put("MONEY", context.get("money"));return map;}@Overridepublic boolean isSendSms(Map context) {return true;}}
  1. 修改原短信内容继承,取钱
/*** * Created by it* Created in 2019年4月13日* Description: 取钱*/
public class SubSms implements SmsDefine{@Overridepublic String smsTemplate(Map context) {String message = "{NAME}在{TIME},取钱{MONEY}。【中国人民银行】";return message;}@Overridepublic Map smsParam(Map context) {Map<String, Object> map = new HashMap<>();map.put("NAME", context.get("name"));map.put("TIME", "2019.4.13");map.put("MONEY", context.get("money"));return map;}@Overridepublic boolean isSendSms(Map context) {// 张三取消发送短信if ("张三".equals(context.get("name"))) {return false;}return true;}}
  1. 更改原短信发送模板
/*** * Created by it* Created in 2019年4月13日* Description: 真正意义上模板,外加SmsDefine桥连*/
public abstract class AbstractSms {// SmsDefine桥连protected SmsDefine smsDefine;// 全局上线文protected Map context = new HashMap<>();public AbstractSms(SmsDefine smsDefine) {this.smsDefine = smsDefine;}/*** 类似Thread提供统一的入口方法*/public void start() {initParam();sendSms();destory();}// 初始化protected abstract void initParam();// 发送短信protected abstract void sendSms();// 结束阶段,可记录日志等protected abstract void destory();
}
  1. 默认实现一套短信模板
public class DefaultSms extends AbstractSms {public DefaultSms(SmsDefine smsDefine) {super(smsDefine);}@Overrideprotected void initParam() {// 模拟参数传入context.put("name", "张三");context.put("money", 100);System.out.println("会话设置成功...");}@Overrideprotected void sendSms() {// 判断是否发送短信, 使用卫语句,校验层次if (!smsDefine.isSendSms(context)) {System.out.println("当前用户取消发送短信");return;}// 获取短信模板String smsTemplate = smsDefine.smsTemplate(context);// 获取参数替换Map smsParam = smsDefine.smsParam(context);// 最终短信String tagerStr = PlaceHolderReplaceUtils.replaceWithMap(smsTemplate, smsParam);// 发送短信,这里直接输出System.out.println("==》发送短信:" + tagerStr);}@Overrideprotected void destory() {System.out.println("原数据归档");System.out.println("日志记录");}}
  1. 测试
public class TestSms {public static void main(String[] args) {// 短信内容SmsDefine smsDefine = new AddSms();// 短信流程AbstractSms sms = new DefaultSms(smsDefine);// 开发发送sms.start();}
}

桥连模式的扩展验证

场景:短信模板数据查询,需要先查询redis缓存中是否有配置,没有再取其他地方配置

  1. 扩展短信功能
public interface CacheSmsDefine extends SmsDefine {String smsTemplateFromCache(Map context);
}
  1. 扩展流程模板
public class RedisCacheSms extends AbstractSms {public RedisCacheSms(SmsDefine smsDefine) {super(smsDefine);}@Overrideprotected void initParam() {// 模拟参数传入context.put("name", "张三");context.put("money", 100);System.out.println("会话设置成功...");}@Overrideprotected void sendSms() {// 判断是否发送短信, 使用卫语句,校验层次if (!smsDefine.isSendSms(context)) {System.out.println("当前用户取消发送短信");return;}// 获取短信模板String smsTemplate = "";if (smsDefine instanceof CacheSmsDefine) {CacheSmsDefine cacheSmsDefine = (CacheSmsDefine) smsDefine;smsTemplate = cacheSmsDefine.smsTemplateFromCache(context);} if (smsTemplate == null || "".equals(smsTemplate)) {smsDefine.smsTemplate(context);System.out.println("将短信模板数据进行缓存设置");}// 获取参数替换Map smsParam = smsDefine.smsParam(context);// 最终短信String tagerStr = PlaceHolderReplaceUtils.replaceWithMap(smsTemplate, smsParam);// 发送短信,这里直接输出System.out.println("==》发送短信:" + tagerStr);}@Overrideprotected void destory() {System.out.println("原数据归档");System.out.println("日志记录");}}

以上改造有两点,将业务流程与业务的具体内容完全解耦,具有以下优点

  1. 可动态扩展短信内容
  2. 可动态扩展业务流程模板
  3. 不修改现有功能

桥连模式,模板模式的改进相关推荐

  1. 设计模式之策略模式+工厂模式+模板模式结合

    设计模式之策略模式+模板模式 为什么总是学不好设计模式 从"登录功能"中发现问题. 首先我们简单的了解功能需求: 于是你开始干活了: 1.控制层代码如下,根据不同的登录方式调用不同 ...

  2. Java设计模式之策略模式+工厂模式+模板模式

    Java设计模式之策略模式+工厂模式+模板模式 1.策略模式+工厂模式+模板模式 个人的理解:实际开发工程中,一些业务很复杂的逻辑使用很多的 if 或者 if···else 语句,不利于维护和扩展,为 ...

  3. 记录策略模式模板模式的一次应用过程

    目录 1.业务背景 2.代码示例 3.总结 1.业务背景 我们的一套H5应用程序前.后端只有一套部署,但是domain确有Fenqile.JiaoYiMao.Mp.ThunderMP.Thunder. ...

  4. 常用设计模式-策略模式+工厂模式+模板模式(使用场景、解决方案)

    在策略模式+工厂模式中,没有使用到模板模式,因为张三和李四的业务逻辑都是调用AAA方法,如果现在在增加一个方法,次方法只需要李四一人去实现BBB方法,此时张三的handel中就会报错,需要张三也去实现 ...

  5. 行为模式(模板模式命令模式备忘录模式)

    目录 模板方法模式(Template) 介绍 实现 命令模式(Command) 介绍 实现 备忘录模式(Memento) 介绍 实现 模板方法模式(Template) 一个抽象类公开定义了执行它的方法 ...

  6. 第十三章行为型模式—模板模式

    文章目录 模板模式 解决的问题 结构 实例 存在的问题 适用场景 JDK源码 - InputStream 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对 ...

  7. 模板方法模式(模板模式)——钩子方法

    豆浆制作问题 编写制作豆浆的程序,说明如下: 制作豆浆的流程选材->添加配料->浸泡->放到豆浆机打碎 通过添加不同的配料,可以制作出不同口味的豆浆 选材.浸泡和放到豆浆机打碎这几个 ...

  8. Java设计模式(七)策略模式 模板模式

    (十三)策略模式 策略图案限定了多个封装算法,该算法可以相互替换包.法的客户.借用还有一位大神的样例. interface ICalculator{public int calculate(Strin ...

  9. 精妙绝伦的设计模式:策略模式+模板模式+工厂模式

    还是以经典的会员价格策略为依托场景: 一.首先加入maven依赖,此依赖用于扫描并获取特定含有特定注解的类 二.定义个一个自定义注解,用来定义并判断价格区间 三.写一个策略接口类,用于定义获取折后价格 ...

  10. C语言实现设计模式—模板模式

    文章目录 C语言实现设计模式-模板模式 模板模式介绍 UML用例说明 实际场景使用 框架结构[共用框架]-通用的串口协议分析函数 不同实现-数据类型区别 C语言实现设计模式-模板模式 模板模式介绍 在 ...

最新文章

  1. 数据呈现 | 20大数据可视化工具测评
  2. mysql远程连接 Host * is not allowed to connect to this MySQL server
  3. java list 数据不重复,Java中List集合去除重复数据的方法
  4. LeetCode 多线程 1117. H2O 生成
  5. C#设置系统日期时间格式
  6. 信息学奥赛一本通 1104:计算书费 | OpenJudge NOI 1.6 03
  7. Go开发报错 -- Golang strings.Builder type undefined
  8. 剑指offer (04):二维数组中的查找 (C++ Python 实现)
  9. 【LeetCode-面试算法经典-Java实现】【129-Sum Root to Leaf Numbers(全部根到叶子结点组组成的数字相加)】...
  10. 双系统Linux(centos\redhat)和window的安装
  11. Mysql常用命令笔记
  12. java枚举转换_java枚举类(转)
  13. sqlserver 日期与字符串之间的转换
  14. DSP指纹识别系统硬件设计
  15. Visio 导出图片时字符间距错乱
  16. 命令与征服2完全版+烈火风暴资料片
  17. Redis应用项目---抢红包功能(一)
  18. 【转载】nuke命令行渲染方法-多线程渲染!
  19. intell idea 使用mave打springboot包的插件
  20. 2016区域赛前冲刺训练

热门文章

  1. oracle数据库表格连接数据库,excel中连接表格数据库-excel怎样连接oracle数据库(白痴级提问)...
  2. ESD静电二极管封装规格,详细介绍
  3. 慧荣SM2258XT-主板CE跳线Toggle土狗跳线合集整理(持续更新)
  4. pta平台c语言作业答案,C语言PTA平台习题与答案.pdf
  5. atmega128 单片机 玩具电子琴 蜂鸣器 电子琴
  6. flashfxp怎么下载文件到本地
  7. 软件体系结构风格复习总结
  8. BP神经网络算法推导过程
  9. 浅析局域网聊天软件的能力
  10. android放大镜无广告,放大镜微件  |  Android 开发者  |  Android Developers