本文主要是介绍【设计模式活用】之代码重构之DAO扮演多个职责的重构案例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在本次关于GPS优化需求项目时,发现相关功能菜单查询页面共同一个DAO接口实现类,紧接着我看了一下listAll,pre,next,countAll方法业务代码高度相似,此已说明该DAO扮演着非单一原则,其承担着 系统多个功能菜单的查询功能。
文章目录
- 1.背景介绍
- 1.1 业务分析
- 1.2 思路分析
- 2、相关类图
- 2.1、executor类图
- 2.2、context类图
- 3、相关源码
- 3.1、AbstractWhereExecutor
- 3.2、InstalledGpsQueryExecutor
- 3.3、TobeUploadGpsQueryExecutor
- 3.4、UnInstalledGpsQueryExecutor
- 3.5、UploadedGpsQueryExecutor
- 3.6、调用方
- 4、归纳总结
1.背景介绍
-
共同之处,就是查询共同表 ca_app_info,或者操作共同Hibernate对象VCaAppInfo。
-
不同之处体现如下方面:1、包含HQL和SQL查询 。2、where条件不同(为了过滤数据以及根据页面表单条件动态判断拼加成一个StringBuffer对象(即SQL/HQL))。
1.1 业务分析
涉及查询的四个方法中(listAll,pre,next,countAll方法业务代码高度相似),代码冗余,不利于维护。
因此,借此机遇,对涉及本期需求GPS查询 四个页面进行重构,提炼出四个单据的实现类,统一继承抽象类,内部维护相关SQL或者HQL查询逻辑,调用方只需构造上线文,
产生不同的实现类即可,提高可扩展,可维护性。重构前代码,点击链接,查看方法:listAll,pre,next,countAll,你就晓得了。
源代码片段
@Overridepublic List<VCaAppInfo> pre(VCaAppInfoId ci, int pn, int defaultPageSize) {// TODO Auto-generated method stubStringBuffer sb = new StringBuffer();sb.append("from VCaAppInfo v where 1=1");List<Object> listParams = new ArrayList<Object>();AbstractWhereExecutor<VCaAppInfoId> whereExecutor;WhereContext whereContext = new WhereContext(ci,sb,listParams,WhereContext.Strategy.HQL);String status = ci.getStatus();if (StringUtil.checkStatus(status)) {sb.append(" and v.id.status in (?)");listParams.add(status);sb.append(" and v.AUserId=? ");listParams.add(ci.getUser().getUserId());/** if("23".equals(status)){ //根据REFUSE_STATUS拒绝状态查询* sb.append(" and v.refuseStatus in (?)");* listParams.add(ci.getRefusestatus()); }else* if("24".equals(status)){ sb.append(" and v.refuseStatus <> 3"); }*/if ("23".equals(status)) { // 根据REFUSE_STATUS拒绝状态查询sb.append(" and v.refuseStatus in (?)");listParams.add(ci.getRefusestatus());} else if ("24".equals(status) && !"3".equals(ci.getRefusestatus())) { // refusestatus// =// 0// 1// 终审sb.append(" and v.refuseStatus <> 3");} else if ("3".equals(ci.getRefusestatus())) { // 3 复核拒绝sb.append(" and v.refuseStatus = 3");}} else if ("80".equals(ci.getStatus())) { // 复审审批页面 显示自己审批的和信贷经理退回审批的// 150123sb.append(" and v.id.status in('23','30')");sb.append(" and v.AUserId=? ");listParams.add(ci.getUser().getUserId());} else if ("-27".equals(status)) { // 经销商上传GPS安装单 150302sb.append(" and (v.isGps ='0' or v.isGps ='2') and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and v.id.status not in('11','12') ");// 经销商用户只能查看该门店单子 其他用户查看所有Set<SyUserDealer> ds = ci.getUser().getSyUserDealers();if (ds.size() != 0) {sb.append(" and v.id.dealerCode in(");Iterator<SyUserDealer> it = ci.getUser().getSyUserDealers().iterator();while (it.hasNext()) {SyUserDealer d = it.next();int dealerCode = d.getId().getDealerCode();sb.append(dealerCode + " ,");}String allhql = sb.substring(0, sb.length() - 1);allhql += ") ";sb.setLength(0);// 清空 后加上sb.append(allhql);}} else if ("-28".equals(status)) { // GPS维护 已上传GPS安装whereExecutor = new InstalledGpsQueryExecutor(whereContext);whereExecutor.execute();} else if ("-29".equals(status)) { // GPS维护whereExecutor = new UnInstallGpsQueryExecutor(whereContext);whereExecutor.execute();} else if ("-30".equals(status)) { // 贷后资料维护sb.append(" and (v.ALOANARRIVE is null or v.ALOANARRIVE!='1') and v.id.status='32' ");if (ci.getIsOld() != null) {sb.append(" and v.isOld=? ");listParams.add(ci.getIsOld());}if (ci.getPostLoanStatus() != null) {// 新车贷后资料上传状态(包括花乡的二手车 即先放款后抵押)if ("0".equals(ci.getPostLoanStatus())) {// 未上传sb.append(" and (v.postLoanStatus is null or v.postLoanStatus='0' ) ");} else if ("1".equals(ci.getPostLoanStatus())) {// 已上传sb.append(" and v.postLoanStatus='1' ");} else if ("2".equals(ci.getPostLoanStatus())) {// 审批退回sb.append(" and v.postLoanStatus='2' ");} else if ("3".equals(ci.getPostLoanStatus())) {// 审批通过sb.append(" and v.postLoanStatus='3' ");}}} else if ("-31".equals(status)) { // 贷后资料维护回退sb.append(" and v.ALOANARRIVE='1' and v.id.status='32' ");} else if ("-32".equals(status)) { // 新车等待上传贷后资料sb.append(" and v.id.status='32' and ifnull(v.ALOANARRIVE,'')!='1' ");if (ci.getIsOld() != null) {sb.append(" and v.isOld=? ");listParams.add(ci.getIsOld());}if (ci.getPostLoanStatus() != null) {if ("0".equals(ci.getPostLoanStatus())) {// 未上传sb.append(" and (v.postLoanStatus is null or v.postLoanStatus='0') ");} else if ("1".equals(ci.getPostLoanStatus())) {// 已上传sb.append(" and v.postLoanStatus='1' ");} else if ("2".equals(ci.getPostLoanStatus())) {// 审批退回sb.append(" and v.postLoanStatus='2' ");} else if ("3".equals(ci.getPostLoanStatus())) {// 审批通过sb.append(" and v.postLoanStatus='3' ");}} else {sb.append(" and ifnull(v.postLoanStatus,'')!='1' and ifnull(v.postLoanStatus,'')!='3' ");// 所有,不显示已上传的申请单和审批通过的}// 经销商用户只能查看该门店单子 其他用户查看所有Set<SyUserDealer> ds = ci.getUser().getSyUserDealers();if (ds.size() != 0) {sb.append(" and v.id.dealerCode in(");Iterator<SyUserDealer> it = ci.getUser().getSyUserDealers().iterator();while (it.hasNext()) {SyUserDealer d = it.next();int dealerCode = d.getId().getDealerCode();sb.append(dealerCode + " ,");}String allhql = sb.substring(0, sb.length() - 1);allhql += ") ";sb.setLength(0);// 清空 后加上sb.append(allhql);}} else if ("-33".equals(status)) {// 经销商GPS安装列表,TODO zhaozhaoxin// 20170411 addsb.append(" and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and status in('15','16','17','18','19','25','26','27','28','29','32') ");// 经销商用户只能查看该门店单子 其他用户查看所有Set<SyUserDealer> ds = ci.getUser().getSyUserDealers();if (ds.size() != 0) {sb.append(" and v.id.dealerCode in(");Iterator<SyUserDealer> it = ci.getUser().getSyUserDealers().iterator();while (it.hasNext()) {SyUserDealer d = it.next();int dealerCode = d.getId().getDealerCode();sb.append(dealerCode + " ,");}String allhql = sb.substring(0, sb.length() - 1);allhql += ") ";sb.setLength(0);// 清空 后加上sb.append(allhql);}} else {sb.append(" and v.id.status in (?)");listParams.add(status);// TODO zhaozhaoxin 20170308 add 进行分组查询if (isRoleQueryData(ci.getUser())) {getUserGroupIds(sb, ci.getUser(), status, true);} else {return null;}}if (ci.getFlowSeq() != null) {sb.append(" and v.flowSeq= ?");listParams.add(ci.getFlowSeq());}if (ci.getDealerName() != null) {sb.append(" and v.id.dealerName like ?");listParams.add("%" + ci.getDealerName() + "%");}if (ci.getAppCode() != null) {sb.append(" and v.id.appCode = ?");listParams.add(ci.getAppCode());}if (ci.getProppserName() != null) {sb.append(" and v.id.proppserName like ?");listParams.add("%" + ci.getProppserName() + "%");}if (ci.getIsLcv() != null) {sb.append(" and v.isLcv = ?");listParams.add(ci.getIsLcv());}if (ci.getAppTime() != null) {sb.append(" and date_format(v.id.appTime,'%Y%m%d') >= ?");listParams.add(DateUtil.getDateFormatE(ci.getAppTime()));}if (ci.getAppTime2() != null) {sb.append(" and date_format(v.id.appTime,'%Y%m%d') <= ?");listParams.add(DateUtil.getDateFormatE(ci.getAppTime2()));}if (ci.getUpdateTime1() != null) {sb.append(" and date_format(v.updateTime,'%Y%m%d') >= ?");listParams.add(DateUtil.getDateFormatE(ci.getUpdateTime1()));}if (ci.getUpdateTime2() != null) {sb.append(" and date_format(v.updateTime,'%Y%m%d') <= ?");listParams.add(DateUtil.getDateFormatE(ci.getUpdateTime2()));}if (ci.getLoanDate1() != null) {sb.append(" and date_format(v.loanTime,'%Y%m%d') >= ?");listParams.add(DateUtil.getDateFormatE(ci.getLoanDate1()));}if (ci.getLoanDate2() != null) {sb.append(" and date_format(v.loanTime,'%Y%m%d') <= ?");listParams.add(DateUtil.getDateFormatE(ci.getLoanDate2()));}sb.append(" order by v.updateTime asc");// 从小到大排序 先提交的在前面List<VCaAppInfo> result = queryByHql(sb.toString(), pn,defaultPageSize, listParams.toArray());return result;}
1.2 思路分析
涉及四个功能菜单
- 1、待上传GPS安装单
- 2、GPS安装单列表
- 3、GPS安装单未上传
- 4、GPS安装单已上传
思路:分析如上四个菜单的查询特征,通过把相同和差异的抽象出来,即提取一个抽象类,通过模板方法,差异部分为抽象类子类,实现差异部分业务逻辑。
2、相关类图
2.1、executor类图
2.2、context类图
3、相关源码
3.1、AbstractWhereExecutor
public abstract class AbstractWhereExecutor<T> implements Predicate<WhereContext> {/*** 上线文*/protected WhereContext<T> context;/*** 参数DTO*/protected T dto;/*** 查询条件*/protected StringBuffer queryWhere;/*** 构造函数* @param context 上线文对象*/public AbstractWhereExecutor(WhereContext<T> context) {this.context = context;}/*** 处理接口*/public void execute() {this.execute((e)->{});}/*** 处理接口* @param after*/public void execute(Consumer<WhereContext> after) {// 初始化this.prepare();// 检查参数this.check(context);// 执行鉴定if(this.test(context)){switch (context.getStrategy()){case SQL:sql();break;case HQL:hql();break;default:break;}}// 后置处理after.accept(context);}/*** 参数检查* @param context*/protected void check(WhereContext context){Assert.notNull(context.getDto(),"DTO对象为空");Assert.notNull(context.getStrategy(),"strategy为空");}/*** 初始化参数*/protected void prepare(){this.dto = this.context.getDto();this.queryWhere = this.context.getQueryWhere();}/*** 由子类实现具体处理SQL条件*/protected abstract void sql();/*** 由子类实现具体处理HQL条件*/protected abstract void hql();
}
3.2、InstalledGpsQueryExecutor
public class InstalledGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {/*** 标示*/protected String gpsFlow;/*** 审批人*/protected Integer approvalUserId;/*** 构造函数** @param context 上线文对象*/public InstalledGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void prepare() {super.prepare();this.gpsFlow = dto.getGpsFlow();this.approvalUserId = dto.getUser().getUserId();}@Overrideprotected void sql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from ca_gps_flow f where f.app_code = v.app_code and f.flow_step = 0 and f.approval_user_id = "+this.approvalUserId+") ");}where.append(" and v.status not in (11,13) and v.is_Gps ='2' and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null and v.manage_Approval_Time is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from Sy_Dealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealer_Code = v.dealer_Code) ");}if (!StringUtil.isBlank(dto.getPostLoanStatus())) {//由于manual_audit_code多个时以";"分割,所以需要使用FIND_IN_SET函数处理 add by 石冬冬 on 2017/9/21where.append(" and v.app_code IN (SELECT app_code FROM Ca_Car_Gps WHERE del_status=1 and FIND_IN_SET ("+dto.getPostLoanStatus()+",replace(manual_audit_code,';',','))>0 ");where.append(" GROUP BY app_code) ");}}@Overrideprotected void hql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from CaGpsFlow f where f.appCode = v.id.appCode and f.flowStep = 0 and f.approvalUserId = " + this.approvalUserId+")");}where.append(" and v.id.status not in (11,13) and v.isGps ='2' and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from SyDealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealerCode = v.id.dealerCode) ");}if (!StringUtil.isBlank(dto.getPostLoanStatus())) {//由于manual_audit_code多个时以";"分割,所以需要使用FIND_IN_SET函数处理 add by 石冬冬 on 2017/9/21where.append(" and v.id.appCode IN (SELECT appCode FROM CaCarGps WHERE delStatus=1 and find_in_set("+dto.getPostLoanStatus()+",replace(manualAuditCode,';',','))>0 ");where.append(" GROUP BY appCode) ");}}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-28".equals(dto.getStatus());}private boolean isMine(){return "mine".equals(gpsFlow);}
}
3.3、TobeUploadGpsQueryExecutor
public class TobeUploadGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {/*** 构造函数** @param context 上线文对象*/public TobeUploadGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void sql() {StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and (v.is_Gps ='0' or v.is_Gps ='2') and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null and v.manage_Approval_Time is not null and v.status not in('11','12') ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.dealer_Code in({0})", StringUtils.join(list,","));where.append(condition);});}@Overrideprotected void hql() {StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and (v.isGps ='0' or v.isGps ='2') and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and v.id.status not in('11','12') ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.id.dealerCode in({0})", StringUtils.join(list,","));where.append(condition);});}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-27".equals(dto.getStatus());}
}
3.4、UnInstalledGpsQueryExecutor
/*** @description: 车贷审批管理》GPS安装单未上传* @Date : 上午10:17 2017/11/17* @Author : 石冬冬-Heil Hitler(dongdong.shi@mljr.com)*/
public class UnInstalledGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {/*** 标示*/protected String gpsFlow;/*** 审批人*/protected Integer approvalUserId;/*** 构造函数** @param context 上线文对象*/public UnInstalledGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void prepare() {super.prepare();this.gpsFlow = dto.getGpsFlow();this.approvalUserId = dto.getUser().getUserId();}@Overrideprotected void sql() {StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from ca_gps_flow f where f.app_code = v.app_code and f.flow_step = 0 and f.approval_user_id = "+this.approvalUserId+")");}where.append(" and v.status not in (11,13) and v.is_Gps ='0' and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null and v.manage_Approval_Time is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from Sy_Dealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealer_Code = v.dealer_Code) ");}}@Overrideprotected void hql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;if(this.isMine()){where.append(" and exists(select 1 from CaGpsFlow f where f.appCode = v.id.appCode and f.flowStep = 0 and f.approvalUserId = "+this.approvalUserId+")");}where.append(" and v.id.status not in (11,13) and v.isGps ='0' and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null");if(!StringUtil.isBlank(dto.getProvince())){where.append(" and exists(select 1 from SyDealer dr where dr.province = '"+dto.getProvince()+"' and dr.dealerCode = v.id.dealerCode) ");}}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-29".equals(dto.getStatus());}private boolean isMine(){return "mine".equals(gpsFlow);}
}
3.5、UploadedGpsQueryExecutor
public class UploadedGpsQueryExecutor extends AbstractWhereExecutor<VCaAppInfoId> {private final String STATUS_SCOPE = "'15','16','17','18','19','25','26','27','28','29','32'";/*** 构造函数** @param context 上线文对象*/public UploadedGpsQueryExecutor(WhereContext context) {super(context);}@Overrideprotected void check(WhereContext context) {super.check(context);SyUser sessionUser = dto.getUser();Assert.notNull(sessionUser,"sessionUser为空");}@Overrideprotected void sql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and v.gps_Fee<>0 and v.gps_Fee !='' and v.gps_Fee is not null and v.manage_Approval_Time is not null and status in("+STATUS_SCOPE+") ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.dealer_Code in({0})", StringUtils.join(list,","));where.append(condition);});}@Overrideprotected void hql() {VCaAppInfoId dto = super.dto;StringBuffer where = super.queryWhere;SyUser sessionUser = dto.getUser();where.append(" and v.gpsFee<>0 and v.gpsFee !='' and v.gpsFee is not null and v.manageApprovalTime is not null and status in("+STATUS_SCOPE+") ");GpsUtil.appendDealerCodes(sessionUser,(list) -> {String condition = MessageFormat.format(" and v.id.dealerCode in({0})", StringUtils.join(list,","));where.append(condition);});}@Overridepublic boolean test(WhereContext context) {VCaAppInfoId dto = (VCaAppInfoId)context.getDto();return "-33".equals(dto.getStatus());}
}
3.6、调用方
4、归纳总结
如上,即使用了模板方法这个设计模式,模板方法也是最通常使用的,即把相同的逻辑骨架抽象处理,由子类实现各自的差异部门。
下面的是我的公众号二维码图片,欢迎关注,或公众号搜索【秋夜无霜】。
这篇关于【设计模式活用】之代码重构之DAO扮演多个职责的重构案例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!