【架构思考】巧用Proxy Pattern增强模块功能

问题

我们的系统A,在运行过程中会查询(调用)一个其它系统B的模块,获取一些股票/债券等的属性。
股票/债券的信息每天更新,但是模块B并不提供历史记录,查询到的总是最新值。

原本每天运行下来也没什么问题,但是,最近业务上有一个新的需求,要求我们能够重跑某一天的数据,且最终结果不变。
问题来了,重跑历史上的一天 Day_Z 的数据时,我们要查询模块B,并获取到 Day_Z 的数据,而不是当前记录。

所以,这里需要一个记录历史数据的功能模块。要么我们(系统A)做,要么别人(系统B)做。
经过一番协(che)商(pi),最终决定我们自己来做。

API分析

A调用B的代码大概如下:

try {
	data = service.get(Stock.class)
			.eq(field, value)
			.filter(filterOption);
	return data;
} catch (Exception e) {
	log(e);
}

其中比较重要的就是这个service变量,它是B提供的接口/类。我们会在xml中进行配置并初始化。使用的时候,直接调用service.getAPI并填入参数即可。

思路

一种解决思路是:每次调用B的API的时候,记录下返回值,这样就得到了当天所有query的返回值集合C。
理论上说,需要重跑数据的时候,query应该是不变的。所以下次直接query集合C即可。

在具体实现的时候,有两种方案:

  • Proxy 代理模式 (AOP)
  • Decorator 装饰模式

代理模式和装饰模式非常类似。

从代码层面看:

  • 代理模式在使用时,直接new一个Proxy类即可,而在Proxy类的内部,会new原有对象。
  • 装饰模式在使用时,就像插座转换头一样,需要new一个原有对象,然后在此基础上再new一个Decorator对象。
// Proxy
ModuleBsService service = new ModuleAsProxy();
data = service.get(Stock.class);

// Decorator
ModuleBsService service = new ModuleBsService();
service = new ModuleAsDecorator(service);
data = service.get(Stock.class);

从使用层面看:

  • 代理模式,更强调在原有功能的基础上,添加一些辅助的功能和流程控制。比如log就是一个典型的场景。
  • 装饰模式,更强调对原有功能进行改进,增强,且可以层层嵌套,不断添加新功能。比如IO流。

选择

最终,我们选择了代理模式,原有如下:

  • 从功能上说,查询和记录是两个相互独立的操作,代理模式更合理。
  • 从实现层面来说,两者代码量相同,代理模式相对更易读,方便理解。
  • 需要改动的类并不是很多,静态代理就可以,也没有必要使用动态代理。

我们需要做的,就是在代理类内,额外加入一个记录数据的操作。

// Constructor
ModuleBsService serviceOri = new ModuleBsService();

// get
data = serviceOri.callOriginalAPI(param);
saveData(data);
return data;

总结

  • Proxy 和 Decorator ,功能上类似,但是侧重点不同。
  • 代理模式是对对象施加控制。
  • 装饰模式是为对象增强功能。
  • 最终选用哪个,还需要考虑程序的易读性。

参考

posted @ 2020-12-11 16:09  MaxStack  阅读(4)  评论(0编辑  收藏  举报