采用模板模式实现公众号/小程序通知

226 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

背景

一般小程序中用户下单后,间隔一段时间后需要给用户推送评价通知,而推送评价通知可能是小程序消息通知,也有可能为公众号消息通知,不管是发送小程序还是发送公众号小通知,其实现流程的步骤都是获取accessToken、构建发送消息体、发送消息。本文将讲解如何通过模板模式来实现消息通知。

简介

模板模式(Template Pattern)又叫模板方法模式,其定义了操作的流程,并将流程中的某些步骤延迟到子类中进行实现,使得子类在不改变操作流程的前提下,即可重新定义该操作的某些特定步骤。

基本原理

图片.png

由上图可知,模板方法模式包含以下两个角色

  • AbstractClass(抽象类):在抽象类中定义了一系列基本操作,这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时在抽象类中实现了一个模板方法,用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
  • ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以及完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。

具体实现

抽象模板类

public abstract class AbstractMessageNotityService
{
   protected Logger logger =LoggerFactory.getLogger(MessageNotityService.class);
    
   
   /**
    * 获取accessToken
    * @return
    */
   public abstract String getAccessToken();
   
   /**
    * 构建消息体
    * @return
    */
   public abstract MessageNotityReq  builderRequestBody();
  
   /**
    * 模板方法
    */
    public void sendMessageNotity()
    {
       //获取token
       String accessToken=getAccessToken();
       
       if(StringUtils.isEmpty(accessToken))
       {
           throw new SysException("accessToken is empty");
       }
       
       //构建请求参数
       MessageNotityReq notifyReq= builderRequestBody();
  
       String params= JSON.toJSONString(notifyReq);
        
        //发送请求
        Result result= HttpClientUtil.getInstance().sendHttpPost(notifyReq.getReqUrl(), params);
        if(result!=null && result.getCode()==200)
        {
            logger.info("send Message success");
        }
        else
        {
            logger.info("send Message error");
        }
    }
}

发送小程序订阅通知

public class AppletMessageNotifyServiceIml extends MessageNotityService
{
    @Override
    public String getAccessToken()
    {
        logger.info("this is Applet get accessToken");
        return "18cb41f506482a1d2c7342c3038d2b9e";
    }

    @Override
    public MessageNotityReq builderRequestBody()
    {
        String reqUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken();
        MessageNotityReq notityReq = new MessageNotityReq();
        notityReq.setReqUrl(reqUrl);
        return notityReq;
    }
}

发送公众通知

public class OfficialMessageNotifyServiceImpl extends MessageNotityService
{
    public String getAccessToken()
    {
        logger.info("this is official get accessToken");
        return "94566d42d837c5bd6c2bbd9dc97349d3";
    }
     
    
    public MessageNotityReq  builderRequestBody()
    {
        String reqUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken(); 
        MessageNotityReq notityReq =new MessageNotityReq();
        notityReq.setReqUrl(reqUrl);
        logger.info("this is official message builder Request Body");
        return notityReq;
    }
  }

测试

@RestController
public class MessageNotifyController
{
   
    @RequestMapping("sendAppletMessageNotiy")
    public Result sendAppletMessageNotiy()
    {
        AppletMessageNotifyServiceIml appletMessageNotifyServiceIml =new AppletMessageNotifyServiceIml();
        appletMessageNotifyServiceIml.sendMessageNotity();
         return Result.success("");
    }
    
    @RequestMapping("sendOfficialMessageNotiy")
    public Result sendOfficialMessageNotiy()
    {
        OfficialMessageNotifyServiceImpl officialMessageNotifyService =new OfficialMessageNotifyServiceImpl();
        officialMessageNotifyService.sendMessageNotity();
         return Result.success("");
    }
}

发送小程序通知消息结果如下:

图片.png

模板模式优缺点

优点

  • 封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
  • 父类中提取了公共的部分代码,便于代码复用。
  • 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

缺点

  • 每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度;
  • 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍,增加了代码的耦合性。

总结

模板方法模式是定义了一个算法骨架,然后每个实现类自己去实现自己的业务逻辑。在Spring、Mybatis、Dubbo等框架中有很好实现案例。实际开发中也被广泛应用,所以大家需要掌握其用法。