Strategy模式 封装不同算法

面对银监会项目中“本次应缴金额”计算公式的变动需求,本文通过策略模式实现了灵活应对。策略模式通过定义接口将变化部分独立出来,以适应不同期次和费用类型的计算。文中详细介绍了策略模式的设计与实现过程。
策略模式(Strategy)说穿了就是通过对接口的定义,将应用中变化的部分独立出来由子类实现,从而实现松耦合。
 
问题的起源来自银监会项目的需求变化,“本次应缴金额”的计算公式有变动。公式计算规则如下:

二、“本次应缴金额”自动运算公式
收缴系统的[收入收缴管理]-[监管收费]-[应缴信息录入]中“本次应缴金额”的自动计算公式需改为:
(一)每年第1期“本次应缴金额”
机构监管费=(上年末实收资本×机构监管费率×风险调整系数)÷2
业务监管费=[(上年末资产总额-实收资本)×业务监管费率×风险调整系数-境外分支机构在所在国家缴纳的监管费]÷2
(二)每年第2期“本次应缴金额”
机构监管费=全年应缴机构监管费-第1次应缴机构监管费=上年末实收资本×机构监管费率×风险调整系数-第1次应缴机构监管费
业务监管费=全年应缴业务监管费-第1次应缴业务监管费=[(上年末资产总额-实收资本)×业务监管费率×风险调整系数-境外分支机构在所在国家缴纳的监管费]-第1次应缴业务监管费
请你公司协助完成收缴系统的修改和调试工作。

拿到需求时单是看到琳琅满目的数据字段我就已经头晕了。。,再看看手中原有的代码,计算公式全是在actionPerform()一个方法内完成的,我如果在原有基础上修改,势必会使用大量if else,绕啊绕,换个人也会头晕。“只在此山中,云深不知处”的意境虽然美,但是不适用在代码中。于是我想到了策略模式。
 
通过观察,公式需要计算
1.       每年需要计算两期:第一期和第二期(废话:P);
2.       每期需要计算两种不同的费用:机构监管费和业务监管费;
 
于是我定义出接口:
 

publicinterface ICountStrategy {
    /**
     *计算机构监管费
     */
    public UFDouble countCorpfee();
   
    /**
     *计算业务监管费
     */
    public UFDouble countBusifee();
}
我是按照计算的费用不同来定义的,也可以按照期次来定义。这样,其他程序员一看代码接口,就知道哦,要计算的是两种费用。

 

publicclass CalStrategyObject {
    private UFDouble receivedfund = null; // 上年末实收资本
    private UFDouble totalfund = null; // 上年末总资产
    private UFDouble riskvalue = null;// 风险调整系数
    private UFDouble corprate = null;// 机构监管费率
    private UFDouble busirate = null;// 业务监管费率
    private UFDouble outerfund = null;// 境外分支机构在所在国家缴纳的监管费
    private UFDouble corpfund1 = null;// 1次应缴机构监管费
    private UFDouble busifund1 = null;// 第一次应缴业务监管费
 
    //setter getter方法
}
由于参与计算的数据项较多,我考虑将它们都封装在一个计算参数类中:

为了节省篇幅,Setter Getter方法我就不写了。通过这个类,其他程序员就知道,原来参与计算的就是这些数据啊!
 
 
 
 
 
 
 
 
 
 
 
 

publicabstractclass AbstractCountStrategy implements ICountStrategy {
    privatebooleanisRefresh = false;
 
    protected CalStrategyObject calobj = null;
 
    /**
     *@paramcalobj用于计算的数据vo
     */
    public AbstractCountStrategy(CalStrategyObject calobj) {
       this.calobj = calobj;
    }
 
    publicvoid setCalStrategyObj(CalStrategyObject calobj) {
       this.calobj = calobj;
    }
}
我定义一个抽象类,把接口和计算项类关联起来:

 
下一步,开始真正实现每期不同费用的算法了。

 

/**
 *第一期的计算公式
 *
 *@authorwuz
 *
 */
publicclass FirstTermCalculator extends AbstractCountStrategy {
 
    public FirstTermCalculator(CalStrategyObject calobj) {
        super(calobj);
    }
 
    /*
     * 业务监管费=[(上年末资产总额-实收资本)¡Á业务监管费率¡Á风险调整系数-境外分支机构在所在国家缴纳的监管费]¡Â2;
     */
    public UFDouble countBusifee() {
        UFDouble totalBusifee = CalculatorUtil.countTotalBusiFee(calobj);
        return totalBusifee.div(2);
    }
 
    /*
     * 每年第1本次应缴金额机构监管费=(上年末实收资本¡Á机构监管费率¡Á风险调整系数)¡Â2
     */
    public UFDouble countCorpfee() {
        UFDouble totalFee = CalculatorUtil.countTotalCorpFee(calobj);
        return totalFee.div(2);
    }
}
实现第一期的计算器:


publicclass SecondTermCalculator extends AbstractCountStrategy {
 
    public SecondTermCalculator(CalStrategyObject calobj) {
        super(calobj);
    }
 
    /*
     * 业务监管费=全年应缴业务监管费-1次应缴业务监管费=[(上年末资产总额-实收资本)¡Á业务监管费率¡Á风险调整系数-境外分支机构在所在国家缴纳的监管费]-1次应缴业务监管费
     */
    public UFDouble countBusifee() {
        UFDouble busifee1 = calobj.getBusifund1();// 1次应缴业务监管费
        UFDouble totalfee = CalculatorUtil.countTotalBusiFee(calobj);// 全年应缴业务监管费
        return totalfee.sub(busifee1);
    }
 
    /*
     * 机构监管费=全年应缴机构监管费-1次应缴机构监管费=上年末实收资本¡Á机构监管费率¡Á风险调整系数-1次应缴机构监管费
     */
    public UFDouble countCorpfee() {
        UFDouble corpfee = CalculatorUtil.countTotalCorpFee(calobj);
        UFDouble orgfee1 = calobj.getCorpfund1();// 1次应缴机构监管费
        return corpfee.sub(orgfee1);
    }
 
}
实现第二期的计算器:

 
这里由于公式中,“(上年末实收资本×机构监管费率×风险调整系数)”和“(上年末资产总额-实收资本)×业务监管费率×风险调整系数-境外分支机构在所在国家缴纳的监管费 ”两个公式多次用到,我将其提炼到一个工具类CalculatorUtil中:

 

publicclass CalculatorUtil {
    /**
     *计算总的机构监管费上年末实收资本¡Á机构监管费率¡Á风险调整系数
     *
     *@paramcalobj
     *@return
     */
    publicstatic UFDouble countTotalCorpFee(CalStrategyObject calobj) {
        UFDouble receivedFund = calobj.getReceivedfund();
        UFDouble riskvalue = calobj.getRiskvalue();
        UFDouble rate = calobj.getCorprate();
        return receivedFund.multiply(rate).multiply(riskvalue);
    }
 
    /**
     *业务监管费总额(上年末资产总额-实收资本)¡Á业务监管费率¡Á风险调整系数-境外分支机构在所在国家缴纳的监管费
     *业务监管费率是一个范围值,不同范围取值不一样
     *
     *
     *@paramcalobj
     *@return
     *@throwsException
     */
    publicstatic UFDouble countTotalBusiFee(CalStrategyObject calobj){
        UFDouble total = calobj.getTotalfund();// 上年末资产总额
        UFDouble receivedFund = calobj.getReceivedfund();// 实收资本
        UFDouble sub = total.sub(receivedFund);//按照(上年末资产总额-实收资本)计算业务监管费
        UFDouble business = BusiRateUtil.getInstance().getBusiFee(sub);
        UFDouble riskrate = calobj.getRiskvalue();// 风险调整系数
        UFDouble outfee = calobj.getOuterfund();// 境外分支机构在所在国家缴纳的监管费
        return business.multiply(riskrate).sub(outfee);
    }
}
这样,客户端的代码就简炼成:


 

publicclass CalculatorFactory {
    /**
     *@paramtype期次
     *@return
     */
    public ICountStrategy createCalculator(int type){
       if(type ==1 ){
           returnnew FirstTermCalculator();
       }else {
           returnnew SecondTermCalculator();
       }
       returnnull;
    }
}
publicclass PayableCalculator {
 
...
privatevoid onCount1() throws Exception {
        CalStrategyObject obj = getCalobj();
        ICountStrategy counter = new FirstTermCalculator(obj);
        UFDouble orgFee = counter.countCorpfee();
        data.setOrgfee(orgFee);
        UFDouble busifee = counter.countBusifee();
        data.setBusifee(busifee);
}
 
...
privatevoid onCount2()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值