模板方法模式实际应用

最近又接到一个任务,需要对接京东实物优惠接口。

由于有些商品的信息、订单的状态等会有变动,所以京东提供了一个消息推送的api接口,只不过这个“推送”是我们自己去拉取。

由于消息的类型很多,所以在拉取请求时需要传入消息类型type,京东返回对应的消息列表,我们后端做完处理后,再调用京东删除推送消息api,传入我们处理的消息ID,删除对应消息,表示我们已消费该消息。

整个流程大致就是这样,以上流程中就只有后端处理部分有不同,其他流程都是一样。

对于这种情况,作为一个有追求的软件工程师,肯定不会说复制粘贴搞定;作为一个有经验的软件工程师,肯定也不会说抽出来写几个方法,然后每次调用。

作为一个又有经验,又有追求的软件工程师,马上想到的就是 模板模式 了。

首先来了解一下模板模式

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

以本次任务来说,我们可以将任务分为多个步骤:
1. 设置消息类型type,请求京东接口,接收对应的返回数据。
2. 处理返回数据。
3. 数据记录到数据库。
4. 调用京东删除消息api。

其中其实只有第2点的算法会有所不同,其他都一样。
所以我们只需将第2点的实现代码延迟到子类中。

模板模式结构

  1. 抽象模板角色
    在这里定义整个算法的骨架。
package com.example.demo.template;

import java.util.List;

public abstract class MsgRefreshAbstract {

    public void refreshMsg(Integer type) {
        // 1. 设置消息类型type,请求京东接口,接收对应的返回数据。
        String jsonStr = getJDMsg(type);
        // 2. 处理返回数据。
        List<Integer> ids = dataProcess(jsonStr);
        // 3. 数据记录到数据库。
        record(ids);
        // 4. 调用京东删除消息api。
        delJDMsg(ids);
    }

    public String getJDMsg(Integer type) {
        // 请求京东数据
        return "{\"ret\":\"success\", \"type\":"+type+",\"result\":[{\"id\": 1}, {\"id\": 2}]}";
    }

    public abstract List<Integer> dataProcess(String jsonStr);

    public void record(List<Integer> ids) {
        ids.forEach(id->{
            System.out.println("insert into database " + id);
        });
    }

    public void delJDMsg(List<Integer> ids) {
        ids.forEach(id->{
            System.out.println("delete jd msg " + id);
        });
    }

}

我们将所有方法都设为public,是因为也许某个消息任务与其他任务不太一样,除了重写第2点,可能还会重写其他点。
如果不希望某个方法被修改,设为private即可。

  1. 具体模板角色
    在这里实现抽象方法。
package com.example.demo.template;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class JDOrderChangeMsg extends MsgRefreshAbstract {
    @Override
    public List<Integer> dataProcess(String jsonStr) {
        System.out.println(jsonStr);
        List<Integer> ids = new ArrayList<>();
        JSONArray resultJson = JSONObject.parseObject(jsonStr).getJSONArray("result");
        for (int i = 0; i < resultJson.size(); i++) {
            ids.add(resultJson.getJSONObject(i).getInteger("id"));
        }
        return ids;
    }

    public static void main(String[] args) {
        MsgRefreshAbstract msgRefresh = new JDOrderChangeMsg();
        msgRefresh.refreshMsg(1);
    }
}

总结

这样做有什么好处?
1. 优雅的实现了代码复用。
2. 业务的实现代码不会影响到整体的代码结构,不用担心以后哪个小白程序员乱改到其他步骤的代码导致该操作出现异常。
3. 即使以后新增其他消息类型也很方便。

当然也有缺点,由于京东的消息类型有很多,所以会有很多的类文件。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据