- 首先在阐述需求之前对一些名词做点解释:
- 商户编号:有使用过POS机刷卡的同学,可能都会注意到POS签购单上有一个商户编号,这个编号有15位,前三位代表收单银行,第四位到第七位代表行政区划代码,第八位到第十一位代表商户类型代码及MCC码,最后四位就没什么特殊的了。
- 手续费:每一笔订单都会产生一笔手续费,从结算给商户的金额中扣取,和刷卡的客户无太多关系,一般按发卡行:收单机构:银联的比例为7:3:1或者8:1:1进行清分。
- 扣率:费率根据商户的类型(MCC)不同而不同,现在民生类的是0.38%的手续费,一般类是0.78%,餐娱类是1.25%。
- 订单:订单就是订单啦,应该没人不理解啦。
- 然后描述需求:
现在针对每一笔订单,都会关联到一个商户;每一个商户关联一个固定商户编号;每个商户编号有不同的扣率。比如:1、按每笔收取固定手续费,没交易一笔订 单,收取5角;2、按百分比收取手续费,比如民生类商户按0.38%收取手续费,封顶金额16元;3、按不同交易金额区间收取不同的手续费,比如 0~5000收取每笔订单1元,5000~50000收取每笔订单5角,大于50000收取每笔订单2角;4、不同交易金额区间按不同百分比收取手续费等 等。
- 具体设计不做赘述,直接上类图:
策略接口StrategyCharge定义了一个计算手续费的方法,有四个实现类StrategyWithCount、StrategyWithCountByStage、StrategyWithRatio和StrategyWithRatioByStage,顾名思义,这四个类分别负责计算1每笔收取固定手续费、2每笔按不同金额区间收取不同手续费、3每笔按固定百分比收取手续费和4每笔按不同金额区间根据不同百分比收取手续的计算。
- 所有类的代码如下:
package src.designpattern.strategy.ex2.model; /** * 扣率实体 * * @author wusj * @time 2015年8月10日 上午11:23:06 */ public class DeductionRate { private String id; /** * 资金范围开始值 */ private String rangeBottom; /** * 资金范围结束值 */ private String rangeTop; /** * 扣率,(0,1)之间表示百分比,大于等于1表示每交易扣款金额(单位为分) */ private String ratio; /** * 最大值 */ private String maximum; /** * 最小值 */ private String minimum; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getRangeBottom() { return rangeBottom; } public void setRangeBottom(String rangeBottom) { this.rangeBottom = rangeBottom; } public String getRangeTop() { return rangeTop; } public void setRangeTop(String rangeTop) { this.rangeTop = rangeTop; } public String getRatio() { return ratio; } public void setRatio(String ratio) { this.ratio = ratio; } public String getMaximum() { return maximum; } public void setMaximum(String maximum) { this.maximum = maximum; } public String getMinimum() { return minimum; } public void setMinimum(String minimum) { this.minimum = minimum; } }
package src.designpattern.strategy.ex2.model; /** * 扣率和商户编码关联关系 * * @author wusj * @date 2015年8月10日 上午11:38:34 */ public class DeRateRelateMerCode { private String id; /** * 扣率ID */ private String decutionRateId; /** * 商户编号ID */ private String merchantCodeId; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getDecutionRateId() { return decutionRateId; } public void setDecutionRateId(String decutionRateId) { this.decutionRateId = decutionRateId; } public String getMerchantCodeId() { return merchantCodeId; } public void setMerchantCodeId(String merchantCodeId) { this.merchantCodeId = merchantCodeId; } }
package src.designpattern.strategy.ex2.model; /** * 商户号实体 * * @author wusj * @time 2015年8月10日 上午11:23:20 */ public class MerchantCode { private String id; private String merchantName; /** * 扣率类型: * 1每笔收取固定手续费; * 2每笔按不同金额区间收取不同手续费; * 3每笔按固定百分比收取手续费; * 4每笔按不同金额区间根据不同百分比收取手续。 */ private String rateType; /** * 手续费计算类 */ private String chargeCalClass; private String others; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getMerchantName() { return merchantName; } public void setMerchantName(String merchantName) { this.merchantName = merchantName; } public String getRateType() { return rateType; } public void setRateType(String rateType) { this.rateType = rateType; } public String getChargeCalClass() { return chargeCalClass; } public void setChargeCalClass(String chargeCalClass) { this.chargeCalClass = chargeCalClass; } public String getOthers() { return others; } public void setOthers(String others) { this.others = others; } }
package src.designpattern.strategy.ex2.model; /** * 订单实体 * * @author wusj * @date 2015年8月10日 上午11:54:43 */ public class Order { private String id; /** * 交易金额(单位分) */ private String amount; /** * 商户编号ID */ private String merchantCodeId; /** * 手续费(单位分) */ private String charge; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getAmount() { return amount; } public void setAmount(String amount) { this.amount = amount; } public String getMerchantCodeId() { return merchantCodeId; } public void setMerchantCodeId(String merchantCodeId) { this.merchantCodeId = merchantCodeId; } public String getCharge() { return charge; } public void setCharge(String charge) { this.charge = charge; } }
package src.designpattern.strategy.ex2.service; import src.designpattern.strategy.ex2.model.Order; /** * 订单接口 * * @author wusj * @date 2015年8月10日 上午11:57:21 */ public interface OrderService { Order insert(Order order); void update(Order order); void delete(String orderId); void query(String orderId); }
package src.designpattern.strategy.ex2.service; /** * 策略接口定义 * * @author wusj * @date 2015年8月10日 上午11:59:55 */ public interface StrategyCharge { /** * 计算手续费 * * @param object * @return 返回手续费的字符串形式,单位为分 */ String calcullateCharge(Object object); }
package src.designpattern.strategy.ex2; import src.designpattern.strategy.ex2.service.StrategyCharge; /** * * * @author wusj * @date 2015年8月10日 上午11:59:24 */ public class ContextCharge { protected StrategyCharge strategyCharge; public String calculateCharge(Object object) { return strategyCharge.calcullateCharge(object); } }
package src.designpattern.strategy.ex2; import src.designpattern.strategy.ex2.model.Order; import src.designpattern.strategy.ex2.service.OrderService; import src.designpattern.strategy.ex2.service.StrategyCharge; /** * 订单接口实现类 * * @author wusj * @date 2015年8月10日 下午1:19:32 */ public class OrderServiceImpl extends ContextCharge implements OrderService { public OrderServiceImpl(StrategyCharge strategyCharge) { this.strategyCharge = strategyCharge; } public Order insert(Order order) { String charge = this.calculateCharge(order); order.setCharge(charge); System.out.println("insert data"); return order; } public void update(Order order) { System.out.println("update data."); } public void delete(String orderId) { System.out.println("delete data."); } public void query(String orderId) { System.out.println("query data."); } }
package src.designpattern.strategy.ex2; import java.util.ArrayList; import java.util.List; import src.designpattern.strategy.ex2.model.DeductionRate; import src.designpattern.strategy.ex2.model.Order; import src.designpattern.strategy.ex2.service.StrategyCharge; /** * 计算每笔收取固定金额手续费的算法 * * @author wusj * @date 2015年8月10日 下午12:38:48 */ public class StrategyWithCount implements StrategyCharge { public String calcullateCharge(Object object) { // 计算订单的手续费,如果不是订单,抛出异常 if (object instanceof Order) { Order order = (Order) object; String merchantCodeId = order.getMerchantCodeId(); // 根据merchantCodeId查询DeRateRelateMerCode,再查询DeductionRate List<DeductionRate> rateList = query(merchantCodeId); DeductionRate rate = rateList.get(0); return rate.getRatio(); } else { throw new UnsupportedOperationException(); } } /** * 模拟查询 * * @param merchantCodeId * @return */ private List<DeductionRate> query(String merchantCodeId) { // 需要实现 DeductionRate rate = new DeductionRate(); rate.setId("123"); // 模拟每笔收取0.5元(即50fen)的手续费 rate.setRatio("50"); List<DeductionRate> list = new ArrayList<DeductionRate>(1); list.add(rate); return list; } }
package src.designpattern.strategy.ex2; import src.designpattern.strategy.ex2.model.Order; import src.designpattern.strategy.ex2.service.StrategyCharge; /** * 每笔按不同金额区间收取不同手续费的算法 * * @author wusj * @date 2015年8月10日 下午12:38:48 */ public class StrategyWithCountByStage implements StrategyCharge { public String calcullateCharge(Object object) { // 计算订单的手续费,如果不是订单,抛出异常 if (object instanceof Order) { // 算法 return ""; } else { throw new UnsupportedOperationException(); } } }
package src.designpattern.strategy.ex2; import java.util.ArrayList; import java.util.List; import src.designpattern.strategy.ex2.model.DeductionRate; import src.designpattern.strategy.ex2.model.Order; import src.designpattern.strategy.ex2.service.StrategyCharge; /** * 计算每笔收取“交易金额*固定百分比”的手续费算法 * * @author wusj * @date 2015年8月10日 下午12:38:48 */ public class StrategyWithRatio implements StrategyCharge { public String calcullateCharge(Object object) { // 计算订单的手续费,如果不是订单,抛出异常 if (object instanceof Order) { Order order = (Order) object; String merchantCodeId = order.getMerchantCodeId(); // 根据merchantCodeId查询DeRateRelateMerCode,再查询DeductionRate List<DeductionRate> rateList = query(merchantCodeId); DeductionRate rate = rateList.get(0); String ratio = rate.getRatio(); String maximum = rate.getMaximum(); String minimum = rate.getMinimum(); Float ratioF = Float.parseFloat(ratio); Float maximumF = (maximum == null || "".equals(maximum)) ? -1f : Float.parseFloat(maximum); Float minimumF = (minimum == null || "".equals(minimum)) ? 0f : Float.parseFloat(minimum); Float amountF = Float.parseFloat(order.getAmount()); Float chargeF = amountF * ratioF; chargeF = chargeF < minimumF ? minimumF : chargeF; chargeF = (maximumF != -1f && chargeF > maximumF) ? maximumF : chargeF; return String.valueOf(Math.round(chargeF)); } else { throw new UnsupportedOperationException(); } } /** * 模拟查询 * * @param merchantCodeId * @return */ private List<DeductionRate> query(String merchantCodeId) { // 需要实现 DeductionRate rate = new DeductionRate(); rate.setId("123"); // 模拟每笔手续交易金额*0.005,封顶手续费10元(1000分) rate.setRatio("0.005"); rate.setMaximum("1000"); List<DeductionRate> list = new ArrayList<DeductionRate>(1); list.add(rate); return list; } }
package src.designpattern.strategy.ex2; import src.designpattern.strategy.ex2.model.Order; import src.designpattern.strategy.ex2.service.StrategyCharge; /** * 每笔按不同金额区间根据不同百分比收取手续 * * @author wusj * @date 2015年8月10日 下午12:38:48 */ public class StrategyWithRatioByStage implements StrategyCharge { public String calcullateCharge(Object object) { // 计算订单的手续费,如果不是订单,抛出异常 if (object instanceof Order) { // 算法 return ""; } else { throw new UnsupportedOperationException(); } } }
package src.designpattern.strategy.ex2; import src.designpattern.strategy.ex2.model.MerchantCode; import src.designpattern.strategy.ex2.model.Order; import src.designpattern.strategy.ex2.service.OrderService; import src.designpattern.strategy.ex2.service.StrategyCharge; /** * 测试类 * * @author wusj * @date 2015年8月10日 下午1:24:23 */ public class MainTest { public static void main(String[] args) { String merchantCodeId = "159"; Order order = new Order(); order.setAmount("100"); order.setId("123"); order.setMerchantCodeId(merchantCodeId); try { OrderService orderService = new OrderServiceImpl( getContextCharge(merchantCodeId)); Order temp = orderService.insert(order); System.out.println(temp.getCharge()); } catch (Exception e) { e.printStackTrace(); } } @SuppressWarnings("rawtypes") static StrategyCharge getContextCharge(String merchantCodeId) throws InstantiationException, IllegalAccessException, ClassNotFoundException { MerchantCode code = getMerchantCode(merchantCodeId); String className = code.getChargeCalClass(); Class clazz = Class.forName(className); StrategyCharge charge = (StrategyCharge) clazz.newInstance(); return charge; } static MerchantCode getMerchantCode(String merchantCodeId) { MerchantCode code = new MerchantCode(); code.setId(merchantCodeId); code.setMerchantName("wusj"); code.setRateType("1"); // 测试每笔固定金额 // code.setChargeCalClass("src.designpattern.strategy.ex2.StrategyWithCount"); // 测试每笔固定比例,且最多可收取的手续费限额 code.setChargeCalClass("src.designpattern.strategy.ex2.StrategyWithRatio"); code.setOthers("others"); return code; } }