最近在做的一项工作从比较模糊的状态到清楚自己需要做什么,在到后面自己考虑如何做?再考虑如何优化,一步一步做出来一个自己还比较满意的东西出来。
在这个的大背景就是项目商业化,如何进行判断商业化指标,简单说就是做一个东西给领导看看,产品到底商业化做到什么程度,经过一段时间梳理处理几十个指标从不通的角度和不同的维度进行比较。
第一版最原始的
最原始的想法很简单,想着就是把数据从业务数据中进行抽离,提取整理放到一个一个到指标明细表中,直接供后期查询使用,但是经过后面梳理发现大量指标的规则是一样的或者说是相似的更准确,就进一步规划。
第二版 进行指标合并,抽离数据
指标分成2个级别,应用维度和部门维度。应用维度进行同类指标合并,减少指标明细表个数,减少工作量,部门维度指标全合并放到一个统计表中,使用统计类型进行区分,再着是为了更好的为前端服务,方便快速查询出需要数据,前端一个看板需要的数据需要几十个指标(包括当前值,上周同期数据,已经周环比),趋势图(日,周,月,季度四个维度),部门是多级,需要提供子部门的汇总信息,如果没有进行指标提前汇总,从几十个标准去算数据,以及进行不同标准的数据,几十个接口,这个页面估计很难做到快速查询,供前端使用的接口,所有经过考虑我们将数据提取使用定时任务进行汇总。
代码实现
第一步从各个系统中抽离指标数据
这一步是最繁琐,但是也没什么好写的,各个业务系统提供指标查询的rpc接口,经过整理将数据直接存到对应的指标明细表中,我们每天夜间使用定时任务拉取数据即可:
不通业务系统之间定时任务编写模版
将各个指标数据合并
这一步也是我最想写的,为啥那,这一部分我感觉如何将代码写的比较容易扩展,写一个统一的模版,让大家直接从自己的业务指标明细表里面些一个查询方法,数据做一个适配即可完成指标的汇总;
想到这我想到:1.使用一个模版设计模式定一套汇总的流程2.使用工厂设计模式进行创建不通的汇总指标使用的”汇总器“(暂时叫这个名吧)但是这样写我想其他人还得去修改工厂中的代码,后来使用spring加定义注解定方式实现
开搞吧:
模版设计模式,其实很简单一句话概括就是:使用抽象类定义一个复杂过程的一些列的步骤,按照我这个步骤最终去做,就可以达到你要实现的目的;
@Component
public abstract class AbstractStatisticsAddCounter {
@Autowired
private IStatisticsCountService statisticsCountService;
public void template(JobParamVo vo){
//1.初始化,这里主要是一些资源的初始化,参数的初始化
this.init(vo);
//2.参数的校验,判断传递参数是否符合我的要求
if(!this.checkParam(vo)){
return;
}
//3.当天的数据清理,这样是为了任务失败后可以重复跑
this.clear(vo);
//4。这个是查询方法,也就是说不通的业务指标自己查询自己的即可
List<DeptCountVo> list = this.query(vo);
//5.数据构建,将业务指标数据按照一定的规则进行整理
Map<String, DeptCountVo> builder = this.builder(list);
//6.保存落库
this.saveData(builder);
}
上面是我针对这一个过程进行的步骤拆分,模版还有一个好处就是将共性的代码就在这个抽象类里面进行实现,经过分析发现:只有1和4需要单独实现,其他的2,3,5,6都可以使用这个抽象类实现,那这样只需要将1,4,定义为抽象方法即可:
其他方法比较简单主要是业务我就不再粘贴了,这也是公司的保密代码。
抽象类的实现:
@AddCounter
public class SolBindAppAddCounter extends AbstractStatisticsAddCounter{
@Override
protected void init(JobParamVo vo) {
vo.setType(StatisticTypeEnum.SOL_BIND.getType());
}
@Override
protected List<DeptCountVo> query(JobParamVo vo) {
查询业务指标数据即可
return null;
}
}
这个地方我们已经实现了目标的一个:即不通的指标只需要查询自己的业务指标即可完成自己的指标汇总工作。
但是这个实现类如何被识别;
注意我们使用了一个@AddCounter
自定义注解
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface AddCounter {
}
如何交由spring管理不同的实现
核心代码
@Component
public class StatisticsAdderFactory implements ApplicationContextAware{
private ApplicationContext applicationContext;
//获取applicationcontext
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//自定义注解处理
public void handler(JobParamVo vo) {
Class<? extends Annotation> annotationClass = AddCounter.class;
Map<String,Object> beanWhithAnnotation = applicationContext.getBeansWithAnnotation(annotationClass);
Set<Map.Entry<String,Object>> entitySet = beanWhithAnnotation.entrySet();
for (Map.Entry<String,Object> entry :entitySet){
Class<? extends Object> clazz = entry.getValue().getClass();//获取bean对象
Object bean = applicationContext.getBean(clazz);
if(Objects.nonNull(bean)&& bean instanceof AbstractStatisticsAddCounter){
((AbstractStatisticsAddCounter) bean).template(vo);
}
}
}
}
StatisticsAdderFactory 这个类原来是使用工厂方法实现的,后来也没修改名称,不知道这样实现是不是很优雅,我个人感觉还可以,同时说接入太方便了,工作直接都省了,你感觉哪?
是否有更好的方案?评论区告诉我,我们大家一起学习进步