模板方法模式可以理解成一个方法模板中留白了部分逻辑交给子类实现,那么不同子类的实例对象调用这个模板类的模板方法时就会使用不同的子类逻辑!

介绍

模板方法模式(TemplateMethod):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
image.png

结构

模板方法需要一个抽象模板类以及多个具体模板类

抽象模板类

定义一个模板方法TemplateMethod()该方法大部分内容为通用逻辑,当时在部分逻辑的处理上进行了留白:PrimitiveOperation1() + PrimitiveOperation2(),让子类重新定义这两个方法的逻辑

  1. public abstract class AbstractClass {
  2. public abstract void PrimitiveOperation1();
  3. public abstract void PrimitiveOperation2();
  4. //模板方法
  5. public void TemplateMethod() {
  6. //通用逻辑...
  7. PrimitiveOperation1(); //需要子类实现
  8. PrimitiveOperation2(); //需要子类实现
  9. //通用逻辑...
  10. }
  11. }

具体模板类

定义两个具体模板类,也就是抽象模板类的子类。他们分别定义了两个留白方法

  1. public class ConcreteClassA extends AbstractClass {
  2. @Override
  3. public void PrimitiveOperation1() {
  4. System.out.println("具体方法A方法1实现");
  5. }
  6. @Override
  7. public void PrimitiveOperation2() {
  8. System.out.println("具体方法A方法2实现");
  9. }
  10. }

调用

在主方法中,创建两个子类,然后调用通用的模板方法就回产生不同的结果:

  1. public class Client {
  2. public static void main(String[] args) {
  3. AbstractClass abstractClass;
  4. abstractClass = new ConcreteClassA();
  5. abstractClass.TemplateMethod();
  6. abstractClass = new ConcreteClassB();
  7. abstractClass.TemplateMethod();
  8. }
  9. }

image.png

例子

在austin项目中,发送消息前需要对消息进行过滤、去重!那么由于有多种去重规则,根据不同平台、不同时间等参数存在多种计算去重规则的逻辑。如果为每个逻辑写一个方法代码会非常冗余。
所以在项目中,使用模板方法定义了通用的去重方法,而通过一些留白让不同子类实现不同逻辑来达到多种去重规则!

模板类

主要逻辑是:通过redis存储消息发送次数,而不同规则构成了不同的key!!
例如:5分钟相同用户收到相同消息需要过滤 : key—> 用户id+消息contentId

ps:时间参数是作为通用参数的

  1. public abstract class AbstractDeduplicationService {
  2. @Autowired
  3. private RedisUtils redisUtils;
  4. public void deduplication(DeduplicationParam param) {
  5. TaskInfo taskInfo = param.getTaskInfo();
  6. Set<String> filterReceiver = new HashSet<>(taskInfo.getReceiver().size());
  7. Set<String> readyPutRedisReceiver = new HashSet<>(taskInfo.getReceiver().size());
  8. List<String> keys = deduplicationAllKey(taskInfo);
  9. Map<String, String> inRedisValue = redisUtils.mGet(keys);
  10. for (String receiver : taskInfo.getReceiver()) {
  11. //deduplicationSingleKey需要子类实现!!
  12. String key = deduplicationSingleKey(taskInfo, receiver);
  13. String value = inRedisValue.get(key);
  14. if (value != null && Integer.valueOf(value) >= param.getCountNum()) {
  15. filterReceiver.add(receiver);
  16. } else {
  17. readyPutRedisReceiver.add(receiver);
  18. }
  19. }
  20. putInRedis(readyPutRedisReceiver, inRedisValue, param);
  21. taskInfo.getReceiver().removeAll(filterReceiver);
  22. }
  23. /**
  24. * 构建去重的Key(abstract,需要子类实现--->不同规则构建不同的key)
  25. */
  26. protected abstract String deduplicationSingleKey(TaskInfo taskInfo, String receiver);
  27. }

实现类

实现类中只需要根据去重规则定义Redis key的生成规则即可!!
image.png
image.png

调用

使用子类,调用模板方法deduplication()!!
image.png