设计模式开发实践(外观、策略、代理)原创
一、背景
项目组接到新需求,在客运站站务系统窗口售票中,分销城际定制客运班线车票。传统汽车客运站班线客流逐年下滑,在网约车影响和政府政策主导下,传统汽车客运站开始寻求积极的业务转型,深度与城际出行、定制客运出行整合。
既支持传统站务系统班线客运–分销至–定制客运售票,也支持定制客运车票–分销至–传统的客运站售票窗口。
1.1 业务分析
- 知彼:分析定制客运分销接口调用逻辑;
- 知我:站务系统窗口售票逻辑,考虑未来支持站务系统二次分销给第三方平台;
1.2 技术分析
- 策略模式:站务分销第三方售票,可能存在多个供应商,支持配置供应商模式;
- 外观模式:站务系统模块较多,内部调用分销接口,应该提供统一接口和方法;
- 代理模式:渠道http调用均是入参、请求、返参,相同功能交由代理类专人专做;
二、流程图
2.1 单一职责原则
客运站站务系统,一般部署在车站内网、集团内网环境。调用第三方的分销接口服务,应该满足单一职责原则,使其业务逻辑清晰,支持独立部署。在我们站务系统中,有一套独立的openapi接口程序,用于内外网数据交互和路由。本文对openapi接口程序不做赘述,以站务系统内部程序代码为主。
三、策略模式实现方式
3.1 策略模式核心
多个ServiceBean可以实现相同的接口,根据ApplicationContext获取到容器中管理的Bean。每个实现类的Bean-name不相同,则实现不同策略。
(ApplicationContext(应用上下文):继承BeanFactory接口,可以用来获取容器中的各种bean组件,注册监听事件,加载资源文件等功能。)
3.2 数据库表设计
如图两个供应商渠道(团子城际出行、飞猪城际出现)(举例),可以配置不同的serviceBeanName。这里也可以不放在数据库表,放在config文件中也是一致的,目的只是策略适配器。
四、代理模式实现方式
4.1 数据库表配置
按照上述供应商的配置,每个供应商有多个接口,而接口超时时间、接口限流次数等等的配置,我们将其放在数据库表中。
思考:
- 多数的外部调用方法,都是通过http方式请求;
- http:http接口请求模式相同,均是url、组装入参、组装出差、请求;
4.2 转换器
public interface IConvert<R> {
// 组装请求入参
void buildReqParams(BaseRqDto reqdto,AdpChannel adpChannel) throws Exception;
// 组装返回参数,用于处理返参
void bildResParams() throws Exception;
// 请求
void doRequest(IHttpManager httpManager,AdpChannel adpChannel) throws Exception;
// 返回返参
R getResult() throws Exception;
// 组装url
void buildReqUrl(MemoryData memoryData,AdpChannel adpChannel, String stationId) throws Exception;
}
4.3 代理类(http请求负责人)
4.4 伪代码
规范大家对http的使用方式,使用代理类的action方法,完成整个从组装url、入参、http、返参组装的系列过程:
/**
* @apiNote 获取线路班次
* @author cll
* @date 2023/3/6
* */
private List<InterCityLineResDto> getLine(InterCityLineReqDto baseRqDto){
IConvert<List<InterCityLineResDto>> convert = new InterCityLineCase<>();
try{
director.action(convert,baseRqDto);
return convert.getResult();
}catch (Exception e){
e.printStackTrace();
}
return new ArrayList<>();
}
五、总结
本次开发过程中使用设计模式主要三方面的目的:
- 做好适配,方便后续同类业务需求开发(能加快后续开发进度),提效;
- 做好定义,约束调用方式,让组内同事都按照一定规范来开发,规范代码;
- 加强思考,锻炼抽象能力;