一、基本描述
1,基本思想:在一个抽象类中公开定义了执行它的方法的模板,它的子类可以按需重写方法的实现,但调用将以抽象类中定义的方式进行。算法只存在于父类中,容易修改,需要修改算法的时候,只需要修改父类的模板方法或者已经实现的步骤,子类就会继承这些修改
2,实现了最大化的代码复用:父类的模板方法和已经实现的步骤会被继承直接使用
3,即统一了算法,又提供了很大的灵活性:父类模板方法确保了算法的结构不变,同时由子类提供部分步骤的实现
4,不足之处:每一个不同的实现都需要不同的子类去实现,导致类的数量增加,系统将变得庞大
5,注意事项:定义的模板方法为final方法,不让子类覆盖
6,使用场景:当要完成某个过程,这个过程需要执行一系列的步骤,这些步骤基本相同,但是其中个别的步骤可能不同,这时就可以使用模板方法模式
二、代码实战
业务场景描述
xxx数据局需要做数据的归集,需要各个业务系统,增量同步自己的数据到数据中心。
代码
SyncTemplate.java
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.converge.entity.SyncLatestId;
import com.converge.entity.SyncRecord;
import com.converge.mapper.SyncLatestIdMapper;
import com.converge.mapper.SyncRecordMapper;
import com.converge.util.SpringContextUtil;
import com.converge.util.WebServiceUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @author sunweidong
*/
public abstract class SyncTemplate {
private static final Object objLock = new Object();
private SyncLatestIdMapper syncLatestIdMapper;
private SyncRecordMapper syncRecordMapper;
/**
* 推送数据
*/
public final <T> void pushData() {
// 查询最近一次同步的表的数据
Integer id = findLatestId();
// 查询表数据信息
List<T> data = findDataById(id);
// 过滤组装文件生成新的List<Map<String, String>>结构
List<Map<String, String>> list = WebServiceUtil.processList(data);
if (list != null && list.size() > 0) {
// 生成xml文件
String xml = WebServiceUtil.generateXML(list);
// 推送数据并得到最近一次推送的数据的ID
Object[] obj = WebServiceUtil.push("", xml);
// 保存同步结果的信息:原始数据的ID,返回的结果,表的名称
saveSyncRecord(getIds(list), obj);
// TODO (author:sunweidong) 判断返回结果的有效性
if (false) {
// 保存最近一次同步的数据的ID
saveLatestId((Integer) obj[0]);
}
}
}
/**
* 查询表数据信息
*
* @param id 主键ID
* @return 查询出来的表数据
*/
protected abstract <T> List<T> findDataById(Integer id);
/**
* 获取表名称
*
* @return 表名称
*/
protected abstract String getTableName();
/**
* 查询最近一次同步的表的数据
*
* @return 最近一次同步的数据ID
*/
private Integer findLatestId() {
QueryWrapper<SyncLatestId> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SyncLatestId::getTableName, getTableName());
SyncLatestId syncLatestId = getSyncLatestIdMapper().selectOne(queryWrapper);
return syncLatestId == null ? 0 : syncLatestId.getTableId();
}
/**
* 保存最近一次同步的数据的ID
*
* @param id 最近一次同步的数据ID
*/
private void saveLatestId(Integer id) {
QueryWrapper<SyncLatestId> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SyncLatestId::getTableName, getTableName());
SyncLatestId syncLatestId = getSyncLatestIdMapper().selectOne(queryWrapper);
if (syncLatestId == null) {
syncLatestId = new SyncLatestId();
syncLatestId.setTableName(getTableName());
syncLatestId.setTableId(id);
getSyncLatestIdMapper().insert(syncLatestId);
} else {
syncLatestId.setTableId(id);
getSyncLatestIdMapper().updateById(syncLatestId);
}
}
/**
* 保存同步结果的信息:原始数据的ID,返回的结果,表的名称
*
* @param ids 原始数据的ID
* @param obj 执行推送返回的结果
*/
private void saveSyncRecord(List<String> ids, Object[] obj) {
SyncRecord syncRecord = new SyncRecord();
syncRecord.setTableName(getTableName());
syncRecord.setContent(JSON.toJSONString(ids));
syncRecord.setRespMsg(JSON.toJSONString(obj));
syncRecord.setCreateTime(new Date());
getSyncRecordMapper().insert(syncRecord);
}
/**
* 获取发送数据的全部ID
*/
private List<String> getIds(List<Map<String, String>> list) {
List<String> ids = new ArrayList<>();
list.stream().forEach(v -> ids.add(v.get("id")));
return ids;
}
private SyncLatestIdMapper getSyncLatestIdMapper() {
if (syncLatestIdMapper == null) {
synchronized (objLock) {
if (syncLatestIdMapper == null) {
syncLatestIdMapper = SpringContextUtil.getBean(SyncLatestIdMapper.class);
}
}
}
return syncLatestIdMapper;
}
private SyncRecordMapper getSyncRecordMapper() {
if (syncRecordMapper == null) {
synchronized (objLock) {
if (syncRecordMapper == null) {
syncRecordMapper = SpringContextUtil.getBean(SyncRecordMapper.class);
}
}
}
return syncRecordMapper;
}
}
ScheduleTask.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author sunweidong
*/
@Component
@EnableScheduling
public class ScheduleTask {
private CaseCurrentServiceImpl caseCurrentService;
@Autowired
ScheduleTask(CaseCurrentServiceImpl caseCurrentService) {
this.caseCurrentService = caseCurrentService;
}
@Scheduled(fixedRate = 60 * 1000)
public void minuteTask() {
caseCurrentService.pushData();
}
}
CaseCurrentServiceImpl.java
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.converge.entity.CaseCurrent;
import com.converge.mapper.CaseCurrentMapper;
import com.converge.service.SyncTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 当前流转案件(CaseCurrent)表服务实现类
*
* @author sunweidong
* @createTime 2021-03-11
*/
@Service("caseCurrentService")
@Slf4j
public class CaseCurrentServiceImpl extends SyncTemplate {
@Autowired
private CaseCurrentMapper caseCurrentMapper;
@Override
protected List<CaseCurrent> findDataById(Integer id) {
QueryWrapper<CaseCurrent> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().ge(CaseCurrent::getId, id);
return caseCurrentMapper.selectList(queryWrapper);
}
@Override
protected String getTableName() {
return "case_current";
}
}
友情提示,以下工具类可以在我的博客找到。
- SpringContextUtil.java
- ReflectPojoUtil.java
- SimpleDateFormatUtil.java