桥梁模式加反射查找服务类的实践
作者:互联网
前言
- 桥梁模式的用意是“将抽象化与实现化脱耦,使得二者可以独立地变化。
- 通常我们使用桥梁模式是为了将两个维度的控制分离开来,通过桥梁模式连接起来,使两个维度通过桥梁轻松的做出多种组合。
- 通过使用桥梁模式,我们不必为每种组合写一套逻辑代码,只需要将每个维度中每种逻辑作为一个实现类实现一次,之后使用桥梁对其进行桥接。
需求
笔者所实践的需求如下:
- 服务类型:报表展示服务
- 报表类型:
-
综合报表
-
创建留存报表
-
ltv报表
-
充值留存报表
-
在线监控报表
-
资源报表
-
设备激活监控
-
充值礼包报表
-
在线统计报表
如上,报表类型一共九种。每种报表的数据要分四个数据源,包括后端数据:(实时数据、离线数据)、前端数据:(客户端数据)、排除其他数据的:真实数据。
后端实现
服务框架:springboot、springcloudAlibaba、mybatis
数据源配置
离线数据源
实时数据源
客户端数据源
真实报表数据源
桥梁定义如下
桥梁中定义固定的realMapper用于指定查看实时报表,offMapper用于指定查看离线报表,baseMapper则是通过输入参数判断出当前所请求的数据源,reportParam是当前请求的参数、queryReport()为请求报表数据的方法。
@Component
public abstract class Report {
@Setter
protected BaseMapper realMapper;
@Setter
protected BaseMapper offMapper;
@Setter
protected BaseMapper baseMapper;
@Setter
protected ReportParam reportParam;
public abstract BaseResult queryReport();
}
桥梁上下文ReportContext 定义如下
主要通过reportFactory方法对桥梁中的各个维度属性进行设置,其中 report.setBaseMapper()、report.setRealMapper()、report.setOffMapper()三个方法通过 getReport()方法中的SpringContextUtil.getBean(ConstantTypes.getT())从枚举类中获取对应的类名,再从spring容器中获取对应的bean。
@Component
@Slf4j
public class ReportContext {
/**
* 报表上下文工厂
*
* @param reportType 报表类型
* @param reportParam 报表参数
* @return 生成好的报表类
*/
public Report reportFactory(String reportType, ReportParam reportParam) {
reportParam.setShowType(StringUtils.isEmpty(reportParam.getShowType()) ? account : reportParam.getShowType());
boolean isUser = accountClient.equals(reportParam.getDataType()) || deviceClient.equals(reportParam.getDataType());
boolean isWhite = account.equals(reportParam.getIsContainWhite());
Boolean shiftDataSource = (Objects.nonNull(reportParam.getShiftDataSource()) && reportParam.getShiftDataSource()) || isWhite;
reportParam.setShiftDataSource(shiftDataSource);
Report report = getReport(reportParam.getDataType(), reportType);
report.setBaseMapper(getBaseMapper(reportType, isUser, isWhite, shiftDataSource));
report.setRealMapper(getBaseMapper(reportType, isUser, isWhite, true));
report.setOffMapper(getBaseMapper(reportType, isUser, false, false));
report.setReportParam(reportParam);
return report;
}
/**
* 获取mapper类型
*
* @param reportType 报表类型
* @param isUser 是否为前端报表
* @param isWhite 是否为白名单报表
* @param shiftDataSource 是否切换数据源
* @return
*/
private BaseMapper getBaseMapper(String reportType, Boolean isUser, Boolean isWhite, Boolean shiftDataSource) {
return SpringContextUtil.getBean(ConstantTypes.getT(reportType, isUser, isWhite, shiftDataSource).getClassName(), BaseMapper.class);
}
/**
* 选择报表类型
*
* @param dateType 数据维度
* @param reportType 报表类型
* @return 报表服务类
*/
private Report getReport(String dateType, String reportType) {
return SpringContextUtil.getBean(ConstantTypes.getT(reportType, dateType).getClassName(), Report.class);
}
}
枚举类ConstantTypes 定义如下
public class ConstantTypes {
@AllArgsConstructor
@Getter
public enum Service_type {
NULL("未知", null, null, null),
roleCom("角色综合报表", ReportConstant.com, ReportConstant.role, "Boss2RoleReportService"),
roleLtv("角色ltv报表", ReportConstant.ltv, ReportConstant.role, "Boss2RoleLtvService"),
roleCreateRetain("角色创建留存报表", ReportConstant.createRetain, ReportConstant.role, "Boss2RoleCreateKeepService"),
roleRechargeRetain("角色充值留存报表", ReportConstant.rechargeRetain, ReportConstant.role, "Boss2RoleRechargeKeepService"),
userCom("账号综合报表", ReportConstant.com, ReportConstant.account, "Boss2UserReportService"),
userLtv("账号ltv报表", ReportConstant.ltv, ReportConstant.account, "Boss2UserLtvService"),
userCreateRetain("账号创建留存报表", ReportConstant.createRetain, ReportConstant.account, "Boss2UserCreateKeepService"),
userRechargeRetain("账号充值留存报表", ReportConstant.rechargeRetain, ReportConstant.account, "Boss2UserRechargeKeepService"),
deviceCom("设备综合报表", ReportConstant.com, ReportConstant.device, "Boss2DeviceReportService"),
deviceLtv("设备ltv报表", ReportConstant.ltv, ReportConstant.device, "Boss2DeviceLtvService"),
deviceCreateRetain("设备创建留存报表", ReportConstant.createRetain, ReportConstant.device, "Boss2DeviceCreateKeepService"),
deviceRechargeRetain("设备充值留存报表", ReportConstant.rechargeRetain, ReportConstant.device, "Boss2DeviceRechargeKeepService"),
clientUserCom("客户端账号综合报表", ReportConstant.com, ReportConstant.accountClient, "Boss2UserReportService"),
clientUserLtv("客户端账号ltv报表", ReportConstant.ltv, ReportConstant.accountClient, "Boss2UserLtvService"),
clientUserCreateRetain("客户端账号创建留存报表", ReportConstant.createRetain, ReportConstant.accountClient, "Boss2UserCreateKeepService"),
clientUserRechargeRetain("客户端账号充值留存报表", ReportConstant.rechargeRetain, ReportConstant.accountClient, "Boss2UserRechargeKeepService"),
clientDeviceCom("客户端设备综合报表", ReportConstant.com, ReportConstant.deviceClient, "Boss2DeviceReportService"),
clientDeviceLtv("客户端设备ltv报表", ReportConstant.ltv, ReportConstant.deviceClient, "Boss2DeviceLtvService"),
clientDeviceCreateRetain("客户端设备创建留存报表", ReportConstant.createRetain, ReportConstant.deviceClient, "Boss2DeviceCreateKeepService"),
clientDeviceRechargeRetain("客户端设备充值留存报表", ReportConstant.rechargeRetain, ReportConstant.deviceClient, "Boss2DeviceRechargeKeepService");
public final String reportTypeName;
public final String reportType;
public final String dateType;
public final String className;
}
@AllArgsConstructor
@Getter
public enum BaseMapper_type {
NULL("未知", null, false, false, false, null),
WhiteOnLineCom("白名单综合报表", ReportConstant.com, false, true, true, "Boss2RealWhiteComReportMapper"),
WhiteOnLineLtv("白名单ltv报表", ReportConstant.ltv, false, true, true, "Boss2RealWhiteLtvReportMapper"),
WhiteOnLineCreateRetain("白名单创建留存报表", ReportConstant.createRetain, false, true, true, "Boss2RealWhiteRetainReportMapper"),
WhiteOnLineRechargeRetain("白名单充值留存报表", ReportConstant.rechargeRetain, false, true, true, "Boss2RealWhiteRechargeRetainReportMapper"),
ClientOnLineCom("前端在线实时综合报表", ReportConstant.com, true, false, true, "Boss2RealUserComMapper"),
ClientOnLineLtv("前端在线实时ltv报表", ReportConstant.ltv, true, false, true, "Boss2RealUserLtvMapper"),
ClientOnLineCreateRetain("前端在线实时创建留存报表", ReportConstant.createRetain, true, false, true, "Boss2RealUserRetainMapper"),
ClientOnLineRechargeRetain("前端在线实时充值留存报表", ReportConstant.rechargeRetain, true, false, true, "Boss2RealUserRechargeRetainMapper"),
OnLineCom("实时综合报表", ReportConstant.com, false, false, true, "Boss2RealComReportMapper"),
OnLineLtv("实时ltv报表", ReportConstant.ltv, false, false, true, "Boss2RealLtvReportMapper"),
OnLineCreateRetain("实时创建留存报表", ReportConstant.createRetain, false, false, true, "Boss2RealRetainReportMapper"),
OnLineRechargeRetain("实时充值留存报表", ReportConstant.rechargeRetain, false, false, true, "Boss2RealRechargeRetainReportMapper"),
ClientOffLineCom("前端离线综合报表", ReportConstant.com, true, false, false, "Boss2UserComMapper"),
ClientOffLineLtv("前端离线ltv报表", ReportConstant.ltv, true, false, false, "Boss2UserLtvMapper"),
ClientOffLineCreateRetain("前端离线创建留存报表", ReportConstant.createRetain, true, false, false, "Boss2UserRetainMapper"),
ClientOffLineRechargeRetain("前端离线充值留存报表", ReportConstant.rechargeRetain, true, false, false, "Boss2UserRechargeRetainMapper"),
OffLineCom("离线综合报表", ReportConstant.com, false, false, false, "Boss2ComMapper"),
OffLineLtv("离线ltv报表", ReportConstant.ltv, false, false, false, "Boss2LtvMapper"),
OffLineCreateRetain("离线创建留存报表", ReportConstant.createRetain, false, false, false, "Boss2CreateKeepMapper"),
OffLineRechargeRetain("离线充值留存报表", ReportConstant.rechargeRetain, false, false, false, "Boss2RechargeKeepMapper");
public final String reportTypeName;
public final String reportType;
public final Boolean isUser;
public final Boolean isWhite;
public final Boolean shiftDataSource;
public final String className;
}
/**
* @param reportType 报表类型
* @param dateType 数据维度
* @return Service_type
*/
public static Service_type getT(String reportType, String dateType) {
return Arrays.stream(Service_type.values()).parallel()
.filter(p -> Objects.equals(reportType, p.reportType) && Objects.equals(dateType, p.dateType))
.findAny()
.orElse(Service_type.NULL);
}
/**
* @param reportType 报表类型
* @param isUser 是否为用户报表
* @param isWhite 是否为白名单报表
* @return BaseMapper_type
*/
public static BaseMapper_type getT(String reportType, Boolean isUser, Boolean isWhite, Boolean shiftDataSource) {
return Arrays.stream(BaseMapper_type.values()).parallel()
.filter(p -> Objects.equals(reportType, p.reportType) && Objects.equals(isUser, p.isUser)
&& Objects.equals(isWhite, p.isWhite) && Objects.equals(shiftDataSource, p.shiftDataSource))
.findAny()
.orElse(BaseMapper_type.NULL);
}
}
桥梁数据维度BaseMapper 定义如下
@Component
public interface BaseMapper {
List getUserReport(Map<String, Object> params);
List getRoleReport(Map<String, Object> params);
List getDeviceReport(Map<String, Object> params);
@Deprecated
List getUserTotalMaxDay(Map<String, Object> params);
@Deprecated
List getRoleTotalMaxDay(Map<String, Object> params);
@Deprecated
List getDeviceTotalMaxDay(Map<String, Object> params);
}
dao层的方法直接继承于此类即可使用接口中定义好的多种维度数据
服务类@Service定义
服务类继承桥梁Report,实现其中的queryReport()方法。
接口@Controller定义
接口中通过reportContext.reportFactory()方法获取设定好所有维度属性的Report类,再通过report.queryReport()方法获取需要的数据
@Controller
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Boss2ComReportController {
private final ReportContext reportContext;
@ResponseBody
@RequestMapping(value = "/queryComReport", method = RequestMethod.POST)
public Boss2CommonReportModel queryComReport(@RequestBody ReportParam reportParam) {
Boss2CommonReportModel boss2CommonReportModel = null;
try {
Report report = reportContext.reportFactory(ReportConstant.com, reportParam);
boss2CommonReportModel = (Boss2CommonReportModel) report.queryReport();
boss2CommonReportModel.ok();
} catch (Exception e) {
boss2CommonReportModel.builder().build().fail(e.getMessage());
log.error("query ComReport fail", e);
}
return boss2CommonReportModel;
}
}
通过以上方法我们将原本九张报表*四个维度 = 36个逻辑简化为 九张报表+四个维度 ,极大的降低了代码量,增加了可读性,毫不客气的说,妈妈再也不用担心产品要改需求了!
标签:反射,false,报表,桥梁,ReportConstant,reportType,true,public,查找服务 来源: https://blog.csdn.net/w4187402/article/details/118764242