从实际生产中看策略模式的应用

May 31, 2018
设计模式 策略模式

字数:32672

基本分析

下列是一套伪代码,用于向银行发起退款。之前的入账流水有的是模拟的,有的是真实的,处理逻辑上基本上是一致的,但是中间的细致过程有不同,比如:真实的退款是要调用招行的接口,虚拟的还是接着虚构一个结果。

过程如下:

定时任务开始
查询待退流水
判断,无,则结束
循环,发起退款
如果是,模拟的,走模拟退款过程(1)
如果是,真实的,走真实退款过程(2)
统计,两者各自成功与失败的数量

定时任务开始,代码在这儿

过程(1)模拟退款
判断,状态非待退,结束
查现是否有退款记录
判断,无,则走创建退款过程(1.2),带个实质为无的标识对象
判断,有
读状态
判断,状态为退款成功,更新入账流水的状态为已退,结束
判断,状态为退款失败,则走创建退款过程(1.2),带个实质为有的标识对象
判断,状态为已申请
**模拟读结果,随机生成结果真或假(这可以作为具体的策略)**
判断,如果真,更新退款记录状态,新增退款成功日志,更新入账流水状态为已退
判断,如果假,更新退款记录状态,新增退款成功日志,更新入账流水状态为已退(这儿有一些重复代码了)

模拟退款,代码在这儿

过程(1.2)创建模拟退款
**模拟依赖结果,随机生成真或假(这可以作为具体的策略)**
判断,如果真(1.2.1)
判断,如果存在退款记录,直接用原记录
判断,如果不存在退款记录,创建对象,并给相关属性赋值
更新退款记录的状态(相对于过程1差异是要多更新回执编号和尝试次数),新增退款已申请日志,新增入账流水日志为已申请退款
(代码与过程1有部分重复)
判断,如果假(1.2.2),直接返回了(这个地方还漏了未做创建申请失败的日志)

执行模拟退款,代码在这儿

过程(2)真实退款,流程与过程(1)非常相似,特别的一点是这个过程(2)还作为服务的业务实现被外部调用
判断,状态非待退,结束
查现是否有退款记录
判断,无,则走创建退款过程(2.2),带个实质为无的标识对象
判断,有
读状态
判断,状态为退款成功,更新入账流水的状态为已退,结束
判断,状态为退款失败,则走创建退款过程(2.2),带个实质为有的标识对象
判断,状态为已申请
**读银行结果(这可以作为具体的策略)**
结果有银行业务数据,执行状态和执行结果两者均成功,则更新退款记录状态,新增退款成功日志,更新入账流水状态为已退
结果无银行业务数据,或以上的其它种情况,更新退款记录状态,新增退款失败日志,更新入账流水状态为失败

真实退款,代码在这儿

过程(2.2)创建真实退款
**打包数据,发给招商,收到反馈(这可以作为具体的策略)**
判断,如果真(2.2.1)
判断,如果存在退款记录,直接用原记录
判断,如果不存在退款记录,创建对象,并给相关属性赋值
更新退款记录的状态(相对于过程2差异是要多更新回执编号和尝试次数),新增退款已申请日志,新增入账流水日志为已申请退款
(代码与过程2有部分重复)
判断,如果假(2.2.2),直接返回了(这个地方还漏了未做创建申请失败的日志)

执行真实退款,代码在这儿

综上,流程有一些重复的实现,细节代码有的重复,有的还有点小差异:
(1)不好改,改一个地方,另一个相仿的地方照着改,看能不能把流程做成同一个
(2)细节不好改,细节一不小心改了一个地方没改另一个地方
(3)小地方的改动,往往比较隐蔽地影响其它。

这些都是导致事件可控难度升级。考虑用策略模式重构,模拟和真实的业务相当于两套不同的策略实现,可以同时载到上下文中被调度。

代码差异

直接看代码的差异,重构前:

2.1定时任务开始

public void execTaskCreateBankRefunds() {
    log.info("定时任务-退款:开始执行");
    
    //获取待退还的流水
    //(1)(2)平台出账记录中不存在出账成功(或在途的)的关联流水的,待退入账,视为有效待退
    List<BankPayment> ps = getBankPaymentsNeedRefund();
    if (ps == null || ps.isEmpty()) return;
    int amount_simu_succ = 0;
    int amount_simu_failed = 0;
    int amount_real_succ = 0;
    int amount_real_failed = 0;
    
    //(3)发起退款申请
    for (BankPayment p : ps) {        
        if (CommConst.TRUE == p.getIs_simulate()) { //模拟退款
            if (simulateRepay(p)) {
                amount_simu_succ++;
            } else {
                amount_simu_failed++;
            }
        } else {  //真实退款
            if (transfer.createRepay(p)) {
                amount_real_succ++;
            } else {
                amount_real_failed++;
            }
        }
    }
    log.info("定时任务-退款:\n{}条待退,(1)处理模拟退款,成功{}条,失败{}条;(2)处理真实退款,成功{}条,失败{}条。\n统计依据:(1)成功指:1退款请求已经存在且成功,2之前失败重新发起成功,3退款请求已经存在查结果为成功(2)失败指:1发起退款申请失败,2查询退款申请请求失败,3查询退款申请的结果为失败"
            , new Object[]{ps.size(), amount_simu_succ, amount_simu_failed, amount_real_succ, amount_real_failed});
}

2.2模拟退款

//模拟退款经办
@Deprecated
public boolean simulateRepay(BankPayment p) {
    //非待退状态的流水不处理
    if (p.getState_payment() != CoreCommConst.STATE_DEPOSIT_WAIT_REFUND) {
        return false;
    }
    //先查有没有退款记录
    BankRefund r = getLatestBankRefundByPayId(p.getId_payment());

    if (r == null) {
        return simulateExecRepay(p, r);            
    } else {// r != null
        //查状态
        switch (r.getState_refund()) {                
            case CoreCommConst.STATE_REFUND_SUCC: //1.之前已经成功过(未有效同步状态字),更新平台入账流水的状态
                changePaymentState(p, EnumMoneyLogPack.REFUND_SUCC);
                return true;
            case CoreCommConst.STATE_REFUND_FAILED: //2.之前失败了,再次发起退款申请
                return simulateExecRepay(p, r);
            case CoreCommConst.STATE_REFUND_APPLYED: //3.之前申请了,查询一下银行处理结果
                boolean succ = generateTrueOrFalse(); //取随机结果
                long curr = System.currentTimeMillis();
                EnumMoneyLogPack pack;
                
                if (succ) {
                    pack = EnumMoneyLogPack.REFUND_SUCC;
                    String comment = getSpecialRefundComment(pack);
                    r.setComment_state(comment);
                    r.setState_refund(CoreCommConst.STATE_REFUND_SUCC);
                    r.setLtm_refund_update(curr);                        
                    createOrUpdateBankRefund(r); //更新退款请求的状态为成功
                    
                    //写退款成功日志
                    RefundLog rl = new RefundLog();
                    rl.setCmb_req_nbr(r.getCmb_req_nbr());
                    rl.setComment_state(comment);
                    rl.setId_ref(0);
                    rl.setId_refund(r.getId_refund());
                    rl.setId_refund_log(idGenerator.nextId());
                    rl.setLtm_state_update(curr);
                    rl.setTimes_create_req(r.getTry_times());
                    createOrUpdateRefundLog(rl);
                    
                    changePaymentState(p, pack); //更新平台入账流水状态为成功
                    return true;
                }
                pack = EnumMoneyLogPack.REPAY_BANK_FAILED;
                String comment = getSpecialRefundComment(pack);
                
                r.setState_refund(CoreCommConst.STATE_REFUND_FAILED);
                r.setLtm_refund_update(curr);
                r.setComment_state(comment);
                createOrUpdateBankRefund(r); //更新退款请求的状态为失败
                
                //写退款失败日志
                RefundLog rl = new RefundLog();
                rl.setCmb_req_nbr(r.getCmb_req_nbr());
                rl.setComment_state(comment);
                rl.setId_ref(0);
                rl.setId_refund(r.getId_refund());
                rl.setId_refund_log(idGenerator.nextId());
                rl.setLtm_state_update(curr);
                rl.setTimes_create_req(r.getTry_times());
                createOrUpdateRefundLog(rl);
                
                changePaymentState(p, pack); //更新平台入账日志
                return false;
            default:
                break;
        }// switch
        return false;
    }        
}

2.3执行模拟退款

@Deprecated
public boolean simulateExecRepay(BankPayment p, BankRefund r) {
    boolean succ = generateTrueOrFalse(); //取随机结果
    
    if (succ) {
        long curr = System.currentTimeMillis();
        int try_times = 1;
        long id_ref_refund = 0; //平台入账关联的退款流水
        long cmb_req_nbr = 0;//请求的编号
        
        if (r != null) {//已经存在申请记录
            try_times = r.getTry_times() + 1;
        }
        EnumMoneyLogPack pack = EnumMoneyLogPack.REPAY_REFUND_COMMIT;
        String comment = String.format("第%d次请求,%s", try_times, pack.getCommentRefund());
        
        if (pack.isNeedAddFlag()  //需要加模拟两字
                //&& prop.isOpen_simulate_payment() //打开了模拟 ,为模拟数据必然是打开了这个开关
                && CommConst.TRUE == p.getIs_simulate()) { //为模拟数据
            comment = "模拟," + comment;
        }            
        
        if (r != null) {//已经存在申请记录
            id_ref_refund = r.getId_refund();
        } else {
            //创建或更新出账记录
            r = new BankRefund();
            id_ref_refund = idGenerator.nextId();
            r.setLtm_refund_create(curr);    
            r.setMoney(p.getMoney());
            r.setType_refund(CoreCommConst.TYPE_REFUND_NORMAL);//此为正常退款业务
            r.setState_refund(CoreCommConst.STATE_REFUND_APPLYED);
            r.setId_bank_member(p.getId_bank_member());
            r.setId_payment_related(p.getId_payment());            
            r.setId_refund(id_ref_refund);            
        }
        r.setComment_state(comment);            
        r.setLtm_refund_update(curr);
        
        cmb_req_nbr = Long.parseLong(StringUtils.getIDStarsWithLetter(0, 3, false));
        r.setCmb_req_nbr(cmb_req_nbr);
        r.setTry_times(try_times);
        
        //提交成功
        createOrUpdateBankRefund(r);
        
        //写退款日志
        RefundLog rl = new RefundLog();
        rl.setCmb_req_nbr(cmb_req_nbr);
        rl.setComment_state(comment);
        rl.setId_ref(try_times == 1 ? p.getId_payment() : 0); //仅第一次退款关联上入账流水ID
        rl.setId_refund(id_ref_refund);
        rl.setId_refund_log(idGenerator.nextId());
        rl.setLtm_state_update(curr);
        rl.setTimes_create_req(try_times);
        
        createOrUpdateRefundLog(rl);
        
        //写流水处理日志和保证金(如果关联上了)日志
        changePaymentState(p, pack, try_times == 1 ? id_ref_refund : 0);
    }
    return succ;
}

2.4真实退款

/**
* 退款,根据平台的入账流水,制造(查询)出账结果
* @param p
* @return
*/
@Deprecated
public boolean createRepay(BankPayment p) {
    //非待退状态的流水不处理
    //if (p.getState_payment() != CoreCommConst.STATE_DEPOSIT_WAIT_REFUND) {
    //    return false;
    //}
    
    //先查有没有退款记录
    BankRefund r = bankService.getLatestBankRefundByPayId(p.getId_payment());
    
    if (r == null) {
        return execRepay(p, r);
    } else {// r != null
        //查状态
        switch (r.getState_refund()) {
            case CoreCommConst.STATE_REFUND_SUCC: //1.之前已经成功过(未有效同步状态字),更新平台入账流水的状态
                bankService.changePaymentState(p, EnumMoneyLogPack.REFUND_SUCC);
                return true;
            case CoreCommConst.STATE_REFUND_FAILED: //2.之前失败了,再次发起退款申请
                return execRepay(p, r);                
            case CoreCommConst.STATE_REFUND_APPLYED: //3.之前申请了,查询一下银行处理结果
                com.test.xml.NTDUMINF.CMBSDKPGK elm = new com.test.xml.NTDUMINF.CMBSDKPGK();
                try {
                    elm.fromXmlFile(TransferService.class.getResource("/xml_template/").getPath() +  "NTDUMINF.xml");
                    elm.getINFO().setLGNNAM(CoreCommConst.LGNNAME);
                    elm.getNTDUMINFX1().setREQNBR(r.getCmb_req_nbr());
                    
                    String xml = elm.toXml();            
                    xml = xml.replace("UTF-8", "GBK");            
                    log.info("发送[查询]请求:\n{}", xml);
                    //发送给招商了
                    String retNet = NetUtil.httpPost(xml);
                    //解释结果
                    com.test.xml.NTDUMINF_RET.CMBSDKPGK elm_ret = new com.test.xml.NTDUMINF_RET.CMBSDKPGK();
                    elm_ret.fromXmlStream(retNet.getBytes("UTF-16"));            
                    log.info("接收[查询]反馈:\n{}", elm_ret.toXml());
                    long curr = System.currentTimeMillis();
                    String errDetails = "";
                    
                    if (com.test.xml.NTDUMINF_RET.INFO_RETCOD.n0
                            != elm_ret.getINFO().getRETCOD()) { //查询请求调用成功    
                        errDetails = elm_ret.getINFO().getERRMSG();
                    } else {//成功,进一步获取子结果                            
                        if ((com.test.xml.NTDUMINF_RET.NTDUMINFZ1_REQSTA.FIN
                                == elm_ret.getNTDUMINFZ1().getREQSTA())//银行完成
                            && (com.test.xml.NTDUMINF_RET.NTDUMINFZ1_RTNFLG.S
                                ==  elm_ret.getNTDUMINFZ1().getRTNFLG())//且成功
                        ){
                            EnumMoneyLogPack pack = EnumMoneyLogPack.REFUND_SUCC;
                            String comment = pack.getCommentRefund();
                            
                            r.setComment_state(comment);
                            r.setState_refund(CoreCommConst.STATE_REFUND_SUCC);
                            r.setLtm_refund_update(curr);                        
                            bankService.createOrUpdateBankRefund(r); //更新退款请求的状态为成功
                            
                            //写退款成功日志
                            RefundLog rl = new RefundLog();
                            rl.setCmb_req_nbr(r.getCmb_req_nbr());
                            rl.setComment_state(comment);
                            rl.setId_ref(0);
                            rl.setId_refund(r.getId_refund());
                            rl.setId_refund_log(idGenerator.nextId());
                            rl.setLtm_state_update(curr);
                            rl.setTimes_create_req(r.getTry_times());
                            bankService.createOrUpdateRefundLog(rl);
                            
                            bankService.changePaymentState(p, EnumMoneyLogPack.REFUND_SUCC); //更新平台入账流水状态为成功
                            
                            return true;
                        }
                        errDetails = String.format("银行执行状态字[%s],结果字[%s]"
                                , elm_ret.getNTDUMINFZ1().getREQSTA().toString()
                                , elm_ret.getNTDUMINFZ1().getRTNFLG().toString());
                    }
                    EnumMoneyLogPack pack = EnumMoneyLogPack.REPAY_BANK_FAILED;
                    String comment = pack.getCommentRefund() + ",详情为:" + errDetails;
                    
                    //结果不成功,下一个周期再重新发起新请求
                    r.setState_refund(CoreCommConst.STATE_REFUND_FAILED);
                    r.setLtm_refund_update(curr);
                    r.setComment_state(comment);
                    bankService.createOrUpdateBankRefund(r); //更新退款请求的状态为失败
                    
                    //写退款失败日志
                    RefundLog rl = new RefundLog();
                    rl.setCmb_req_nbr(r.getCmb_req_nbr());
                    rl.setComment_state(comment);
                    rl.setId_ref(0);
                    rl.setId_refund(r.getId_refund());
                    rl.setId_refund_log(idGenerator.nextId());
                    rl.setLtm_state_update(curr);
                    rl.setTimes_create_req(r.getTry_times());
                    bankService.createOrUpdateRefundLog(rl);                        
                    
                    bankService.changePaymentState(p, EnumMoneyLogPack.REPAY_BANK_FAILED); //更新平台入账流水状态为失败
                    return false;
                } catch (LtException | IOException e) {
                    //请求异常,忽略流水状态的维护
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }// switch
        return false;
    }
}

2.5执行真实退款

//退款经办
@Deprecated
private boolean execRepay(BankPayment p, BankRefund r) {
    com.test.xml.NTOPRDMR.CMBSDKPGK elm = new com.test.xml.NTOPRDMR.CMBSDKPGK();
    try {
        elm.fromXmlFile(TransferService.class.getResource("/xml_template/").getPath() +  "NTOPRDMR.xml");
        elm.getINFO().setLGNNAM(CoreCommConst.LGNNAME); 
        elm.getNTOPRDMRX1().setSETNBR(p.getSetnbr());//套号
        elm.getNTOPRDMRX1().setTRXNBR(p.getTrxnbr());//流水号
        elm.getNTOPRDMRX1().setTRSAMT(p.getMoney());
        elm.getNTOPRDMRX1().setDUMNBR(String.format("%010d", p.getId_bank_member()));
        elm.getNTOPRDMRX1().setEPTDAT(StringUtils.formatCurrDate(StringUtils.getDateFormat(CoreCommConst.FORMAT_DATE_YMD)));
        elm.getNTOPRDMRX1().setRPYACC(p.getPay_acc_no());
        elm.getNTOPRDMRX1().setRPYNAM(p.getPay_acc_name());
        elm.getNTOPRDMRX1().setINTFLG("N");//是否退息,固定为N
        long id_ref_post = idGenerator.nextId();
        elm.getNTOPRDMRX1().setYURREF(id_ref_post);
        
        String xml = elm.toXml();            
        xml = xml.replace("UTF-8", "GBK");            
        log.info("发送[退款]请求:\n{}", xml);
        //发送给招商了
        String retNet = NetUtil.httpPost(xml);
        
        //解释结果
        com.test.xml.NTOPRDMR_RET.CMBSDKPGK elm_ret = new com.test.xml.NTOPRDMR_RET.CMBSDKPGK ();
        elm_ret.fromXmlStream(retNet.getBytes("UTF-16"));            
        log.info("接收[退款]反馈:\n{}", elm_ret.toXml());
        
        int ret_code = elm_ret.getINFO().getRETCOD();
        
        if (ret_code != 0) {
            return false;
        } else {//成功,增加请求的记录
            long curr = System.currentTimeMillis();
            int try_times = 1;
            long id_ref_refund = 0; //平台入账关联的退款流水
            long cmb_req_nbr = 0;//请求的编号
            
            if (r != null) {//已经存在申请记录
                try_times = r.getTry_times() + 1;
            }
            EnumMoneyLogPack pack = EnumMoneyLogPack.REPAY_REFUND_COMMIT;
            String comment = String.format("第%d次请求,%s", try_times, pack.getCommentRefund());
        
            if (r != null) {//已经存在申请记录
                id_ref_refund = r.getId_refund();
            } else {
                //创建或更新出账记录
                r = new BankRefund();
                id_ref_refund = idGenerator.nextId();
                r.setLtm_refund_create(curr);    
                r.setMoney(p.getMoney());
                r.setType_refund(CoreCommConst.TYPE_REFUND_NORMAL);//此为正常退款业务
                r.setState_refund(CoreCommConst.STATE_REFUND_APPLYED);
            }
            r.setComment_state(comment);
            r.setId_bank_member(p.getId_bank_member());
            r.setId_payment_related(p.getId_payment());            
            r.setId_refund(id_ref_refund);            
            r.setLtm_refund_update(curr);
            cmb_req_nbr = elm_ret.getNTOPRRTNZ().getREQNBR();
            r.setCmb_req_nbr(cmb_req_nbr);
            r.setTry_times(try_times);
            
            //提交成功
            bankService.createOrUpdateBankRefund(r);
            
            //写退款日志
            RefundLog rl = new RefundLog();
            rl.setCmb_req_nbr(cmb_req_nbr);
            rl.setComment_state(comment);
            rl.setId_ref(try_times == 1 ? p.getId_payment() : 0); //仅第一次退款关联上入账流水ID
            rl.setId_refund(id_ref_refund);
            rl.setId_refund_log(idGenerator.nextId());
            rl.setLtm_state_update(curr);
            rl.setTimes_create_req(try_times);
            
            bankService.createOrUpdateRefundLog(rl);
            
            //写流水处理日志和保证金(如果关联上了)日志
            bankService.changePaymentState(p,  pack, id_ref_refund);
            return true;
        }            
    } catch (LtException | IOException e) {            
        e.printStackTrace();
    }        
    return false;
}

可见,有重复的流程造成了一定的代码重复,重构后如下:

public void execTaskCreateBankRefunds() {
    log.info("定时任务-退款:开始执行");
    
    //获取待退还的流水
    //(1)(2)平台出账记录中不存在出账成功(或在途的)的关联流水的,待退入账,视为有效待退
    List<BankPayment> ps = getBankPaymentsNeedRefund();
    if (ps == null || ps.isEmpty()) return;
    int amount_simu_succ = 0;
    int amount_simu_failed = 0;
    int amount_real_succ = 0;
    int amount_real_failed = 0;
    
    AbstractRefundStategy simulateExector = new SimulateRepay(this, idGenerator);
    AbstractRefundStategy actualExector = new ActualRepay(this, idGenerator);
    
    //(3)发起退款申请
    for (BankPayment p : ps) {        
        if (CommConst.TRUE == p.getIs_simulate()) { //模拟退款
            if (simulateExector.createRefund(p)) {
                amount_simu_succ++;
            } else {
                amount_simu_failed++;
            }
        } else {  //真实退款
            if (actualExector.createRefund(p)) {
                amount_real_succ++;
            } else {
                amount_real_failed++;
            }
        }
    }
    log.info("定时任务-退款:\n{}条待退,(1)处理模拟退款,成功{}条,失败{}条;(2)处理真实退款,成功{}条,失败{}条。\n统计依据:(1)成功指:1退款请求已经存在且成功,2之前失败重新发起成功,3退款请求已经存在查结果为成功(2)失败指:1发起退款申请失败,2查询退款申请请求失败,3查询退款申请的结果为失败"
            , new Object[]{ps.size(), amount_simu_succ, amount_simu_failed, amount_real_succ, amount_real_failed});
}
public abstract class AbstractRefundStategy {
    private final Logger log = LoggerFactory.getLogger(AbstractRefundStategy.class);
    protected SnowflakeIdWorker idGenerator;
    protected BankService bankService;    
    protected TransferService transfer;
    
    protected EnumMoneyLogPack pack;
    
    AbstractRefundStategy(BankService bankService, SnowflakeIdWorker idGenerator){
        this.bankService = bankService;
        this.idGenerator = idGenerator;
    }
    
    public EnumMoneyLogPack getPack() {
        return pack;
    }
    
    protected void setPack(EnumMoneyLogPack pack) {
        this.pack = pack;
    }
    
    private BankRefund initBreforeCreateRefund(BankRefund r, BankPayment p){
        long curr = System.currentTimeMillis();
        int try_times = 1;
        
        if (r != null) {
            try_times = r.getTry_times() + 1;
        } else {
            r = new BankRefund();
            r.setId_refund(idGenerator.nextId());
            r.setLtm_refund_create(curr);        
            r.setType_refund(CoreCommConst.TYPE_REFUND_NORMAL);//此为正常退款业务
            r.setState_refund(CoreCommConst.STATE_REFUND_APPLYED);
            
            r.setMoney(p.getMoney());
            r.setId_bank_member(p.getId_bank_member());
            r.setId_payment_related(p.getId_payment());
        }
        r.setLtm_refund_update(curr);
        r.setTry_times(try_times);
        return r;
    }
    
    public boolean createRefund(BankPayment p){
        //非待退状态的流水不处理
        if (CoreCommConst.STATE_DEPOSIT_WAIT_REFUND != p.getState_payment() //非待退
                && CoreCommConst.STATE_DEPOSIT_LOSE != p.getState_payment() //非罚没 TODO 暂时能后台处理
                ) {
            return false;
        }
        //先查有没有退款记录
        BankRefund r = bankService.getLatestBankRefundByPayId(p.getId_payment());
        long id_ref_payment = 0;

        if (r == null) {
            r = execCreateRefund(initBreforeCreateRefund(r, p), p);
        } else {// r != null
            id_ref_payment  = r.getId_payment_related();
            //查状态
            switch (r.getState_refund()) {                
                case CoreCommConst.STATE_REFUND_SUCC: //1.之前已经成功过(未有效同步状态字),更新平台入账流水的状态,这种情况不太可能出现
                    bankService.changePaymentState(p, EnumMoneyLogPack.REFUND_SUCC);
                    return true;
                case CoreCommConst.STATE_REFUND_FAILED: //2.之前失败了,再次发起退款申请
                    if (r.getTry_times() >= CoreCommConst.TIMES_TRY) { //10次为限,放弃退款
                        log.info("放弃退款,尝试次数达到10次,退款流水号{}", r.getId_refund());
                        setPack(EnumMoneyLogPack.REFUND_GIVEUP);
                        r.setComment_state(pack.getCommentRefund());
                    } else {
                        r = execCreateRefund(initBreforeCreateRefund(r, p), p);
                    }
                    break;
                case CoreCommConst.STATE_REFUND_APPLYED: //3.之前申请了,查询一下银行处理结果
                    r = refreshRefund(r);
                    break;
                default:
                    r = null;
                    break;
            }
        }
        
        if (r != null && pack != null) {
            //创建或更新退款            
            bankService.createOrUpdateBankRefund(r);
            
            //创建退款日志
            RefundLog rl = new RefundLog();
            rl.setCmb_req_nbr(r.getCmb_req_nbr());
            rl.setComment_state(r.getComment_state());
            rl.setId_ref(id_ref_payment == 0 ? p.getId_payment() : 0); //仅第一次时有值
            rl.setId_refund(r.getId_refund());
            rl.setId_refund_log(idGenerator.nextId());
            rl.setLtm_state_update(r.getLtm_refund_update());
            rl.setTimes_create_req(r.getTry_times());
            bankService.createOrUpdateRefundLog(rl);
            
            //更新入账银行流水日志            
            bankService.changePaymentState(p, getPack()
                    , id_ref_payment == 0 ? r.getId_refund() : 0);  //仅在初次创建时,关联ID
            
            return CoreCommConst.STATE_REFUND_SUCC == r.getState_refund();
        }
        return false;
    }
    /**
     * 已申请的退款最新情况刷新,相当于读
     * @return
     */
    abstract BankRefund refreshRefund(BankRefund exists);
    /**
     * 执行要创建的对象的生成
     * @param exists
     * @return
     */
    abstract BankRefund execCreateRefund(BankRefund exists, BankPayment p);
}
/**
* 真实退款
* @author ta
*
*/
public class ActualRepay extends AbstractRefundStategy {
     private final Logger log =  LoggerFactory.getLogger(ActualRepay.class);
     public ActualRepay(BankService bankService,  SnowflakeIdWorker idGenerator) {
          super(bankService, idGenerator);
     }
     @Override
     BankRefund refreshRefund(BankRefund r) {
          long ltm_update = System.currentTimeMillis();
          int state = r.getState_refund();
          String errDetails = null;
          
          com.test.xml.NTDUMINF.CMBSDKPGK elm = new  com.test.xml.NTDUMINF.CMBSDKPGK();
          
          try {
               elm.fromXmlFile(TransferService.class.getResource("/xml_template/").getPath() +  "NTDUMINF.xml");
               elm.getINFO().setLGNNAM(CoreCommConst.LGNNAME);
               elm.getNTDUMINFX1().setREQNBR(r.getCmb_req_nbr());
              
              String xml = elm.toXml();
              xml = xml.replace("UTF-8", "GBK");
              log.info("发送[查询退款结果]请求:\n{}", xml);
              //发送给招商了
              String retNet = NetUtil.httpPost(xml);
              //解释结果
              com.test.xml.NTDUMINF_RET.CMBSDKPGK  elm_ret = new com.test.xml.NTDUMINF_RET.CMBSDKPGK();
               elm_ret.fromXmlStream(retNet.getBytes("UTF-16"));              
              log.info("接收[查询退款结果]反馈:\n{}",  elm_ret.toXml());
              
              if  (com.test.xml.NTDUMINF_RET.INFO_RETCOD.n0
                        != elm_ret.getINFO().getRETCOD())  { //查询请求调用返回为不成功
                   setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
                   state =  CoreCommConst.STATE_REFUND_FAILED;
                   errDetails =  elm_ret.getINFO().getERRMSG();
              } else {//成功,进一步获取子结果                              
                   if  ((com.test.xml.NTDUMINF_RET.NTDUMINFZ1_REQSTA.FIN
                             ==  elm_ret.getNTDUMINFZ1().getREQSTA())//银行完成
                        &&  (com.test.xml.NTDUMINF_RET.NTDUMINFZ1_RTNFLG.S
                             ==   elm_ret.getNTDUMINFZ1().getRTNFLG())//且成功
                   ){//查询成功
                        setPack(EnumMoneyLogPack.REFUND_SUCC);
                        state =  CoreCommConst.STATE_REFUND_SUCC;
                   } else {//结果为不成功
                        setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
                        state =  CoreCommConst.STATE_REFUND_FAILED;
                        
                        errDetails = String.format("银行执行状态字[%s],结果字[%s]"
                                  ,  elm_ret.getNTDUMINFZ1().getREQSTA().toString()
                                  ,  elm_ret.getNTDUMINFZ1().getRTNFLG().toString());
                   }
              }
          } catch (LtException | IOException e) {
              //啥也不干
               //setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
              //state =  CoreCommConst.STATE_REFUND_FAILED;
              //errDetails = "请求银行查询退款结果时异常";
              
              e.printStackTrace();
          }
          String comment = pack.getCommentRefund()
                   + (errDetails == null? "" : ",详情为:"  + errDetails);
          
          r.setComment_state(comment);
          r.setState_refund(state);
          r.setLtm_refund_update(ltm_update);
          return r;
     }
     @Override
     BankRefund execCreateRefund(BankRefund r,  BankPayment p) {
          String errDetails = null;
          
          com.test.xml.NTOPRDMR.CMBSDKPGK elm = new  com.test.xml.NTOPRDMR.CMBSDKPGK();
          
          try {
               elm.fromXmlFile(TransferService.class.getResource("/xml_template/").getPath() +  "NTOPRDMR.xml");
               elm.getINFO().setLGNNAM(CoreCommConst.LGNNAME);
               elm.getNTOPRDMRX1().setSETNBR(p.getSetnbr());//套号
               elm.getNTOPRDMRX1().setTRXNBR(p.getTrxnbr());//流水号
               elm.getNTOPRDMRX1().setTRSAMT(p.getMoney());
               elm.getNTOPRDMRX1().setDUMNBR(String.format("%010d",  p.getId_bank_member()));
               elm.getNTOPRDMRX1().setEPTDAT(StringUtils.formatCurrDate(StringUtils.getDateFormat(CoreCommConst.FORMAT_DATE_YMD)));
               elm.getNTOPRDMRX1().setRPYACC(p.getPay_acc_no());
               elm.getNTOPRDMRX1().setRPYNAM(p.getPay_acc_name());
              elm.getNTOPRDMRX1().setINTFLG("N");//是否退息,固定为N          
               elm.getNTOPRDMRX1().setYURREF(idGenerator.nextId());  //这个地方的业务参考号到底有没有什么影响
              
              String xml = elm.toXml();             
              xml = xml.replace("UTF-8", "GBK");              
              log.info("发送[退款]请求:\n{}", xml);
              //发送给招商了
              String retNet = NetUtil.httpPost(xml);
              
              //解释结果
              com.test.xml.NTOPRDMR_RET.CMBSDKPGK  elm_ret = new com.test.xml.NTOPRDMR_RET.CMBSDKPGK ();
               elm_ret.fromXmlStream(retNet.getBytes("UTF-16"));              
              log.info("接收[退款]反馈:\n{}",  elm_ret.toXml());
              
              int ret_code =  elm_ret.getINFO().getRETCOD();
              
              if (ret_code != 0) {
                   setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
                   r.setState_refund(CoreCommConst.STATE_REFUND_FAILED);
                   errDetails =  elm_ret.getINFO().getERRMSG();
              } else {//成功,增加请求的记录
                   setPack(EnumMoneyLogPack.REPAY_REFUND_COMMIT);
                   r.setCmb_req_nbr(elm_ret.getNTOPRRTNZ().getREQNBR());
              }             
          } catch (LtException | IOException e) {         
               setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
               r.setState_refund(CoreCommConst.STATE_REFUND_FAILED);
              errDetails = "请求银行发起退款时异常";
              
              e.printStackTrace();
          }    
          String comment = String.format("第%d次退款请求,%s", r.getTry_times(), pack.getCommentRefund())
                   + (errDetails == null? "" : ",详情为:"  + errDetails);
          r.setComment_state(comment);
          
          return r;
     }
}
public class SimulateRepay extends AbstractRefundStategy  {
     
     public SimulateRepay(BankService bankService,  SnowflakeIdWorker idGenerator) {
          super(bankService, idGenerator);
     }
     @Override
     BankRefund refreshRefund(BankRefund r) {
          boolean succ =  bankService.generateTrueOrFalse(); //取随机结果
          long ltm_update = System.currentTimeMillis();
          int state = 0;
          
          if (succ) { //假定读到的情况是退款成功
              setPack(EnumMoneyLogPack.REFUND_SUCC);
              state = CoreCommConst.STATE_REFUND_SUCC;
              
          } else {//假定读到的情况是退款失败
               setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
              state = CoreCommConst.STATE_REFUND_FAILED;
          }
          String comment =  bankService.getSpecialRefundComment(getPack());
          r.setComment_state(comment);
          r.setState_refund(state);
          r.setLtm_refund_update(ltm_update);
          
          return r;
     }
     @Override
     BankRefund execCreateRefund(BankRefund r,  BankPayment p) {
          String errDetails = null;
          boolean succ_query =  bankService.generateTrueOrFalse(); //取随机结果
              
          if (succ_query) {//模拟请求银行,成功
              boolean succ_result =  bankService.generateTrueOrFalse(); //取随机结果
              
              if (succ_result) {
                   setPack(EnumMoneyLogPack.REPAY_REFUND_COMMIT);
                   r.setCmb_req_nbr(Long.parseLong(StringUtils.getIDStarsWithLetter(0, 3, false)));
              } else {
                   setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
                   r.setState_refund(CoreCommConst.STATE_REFUND_FAILED);
                   errDetails = "[这里是银行业务处理结果为非正常的描述]";
              }
          } else { //模拟请求银行,失败
               setPack(EnumMoneyLogPack.REPAY_BANK_FAILED);
               r.setState_refund(CoreCommConst.STATE_REFUND_FAILED);
              errDetails = "请求银行发起退款时异常";
          }
          String comment = String.format("第%d次退款请求,%s", r.getTry_times(), pack.getCommentRefund())
                   + (errDetails == null? "" : ",详情为:"  + errDetails);
          r.setComment_state(comment);
          
          return r;
     }
}

代码量对比:
(1)重构前374行,重构后332行
(2)重构前16426字,重构后14272字

从量上看,相差并不是很大,从代码的结构来看,重构后清晰不少,而且解决了一些细节问题,整合后较好维护。


loading