Strategy模式 封装不同算法

策略模式(Strategy) 说穿了就是通过对接口的定义,将应用中变化的部分独立出来由子类实现,从而实现松耦合。
 
问题的起源来自银监会项目的需求变化,“本次应缴金额”的计算公式有变动。公式计算规则如下:

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

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

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

 

public class 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 方法我就不写了。通过这个类,其他程序员就知道,原来参与计算的就是这些数据啊!
 
 
 
 
 
 
 
 
 
 
 
 

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

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

 

/**
  * 第一期的计算公式
  *
  * @author wuz
  *
  */
public class 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);
    }
}
实现第一期的计算器:


public class 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 中:

 

public class CalculatorUtil {
    /**
      * 计算总的机构监管费 上年末实收资本 ¡Á 机构监管费率 ¡Á 风险调整系数
      *
      * @param calobj
      * @return
      */
    public static UFDouble countTotalCorpFee(CalStrategyObject calobj) {
        UFDouble receivedFund = calobj.getReceivedfund();
        UFDouble riskvalue = calobj.getRiskvalue();
        UFDouble rate = calobj.getCorprate();
        return receivedFund.multiply(rate).multiply(riskvalue);
    }
 
    /**
      * 业务监管费总额 ( 上年末资产总额 - 实收资本 )¡Á 业务监管费率 ¡Á 风险调整系数 - 境外分支机构在所在国家缴纳的监管费
      * 业务监管费率是一个范围值,不同范围取值不一样
      *
      *
      * @param calobj
      * @return
      * @throws Exception
      */
    public static 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);
    }
}
这样,客户端的代码就简炼成:


 

public class CalculatorFactory {
    /**
      * @param type 期次
      * @return
      */
    public ICountStrategy createCalculator( int type){
       if (type ==1 ){
           return new FirstTermCalculator();
       } else {
           return new SecondTermCalculator();
       }
       return null ;
    }
}
public class PayableCalculator {
 
...
private void 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);
}
 
...
private void onCount2()

你可能感兴趣的:(算法,项目管理,云计算)