根据不同的输入差异,应用不同的规则,得出不同的输出值
这种情况就适合策略模式。
需求:
计算一个订单运费的适合,会根据重量和目的地有各种计费规则:固定运费,满XX包邮,某几个省份包邮,超过多少重量加价多少等等。
如果选择了固定运费:让你设置一个固定运费是多少元,固定运费20元。
{“fixed_freigt”: 20}
比如说,选择了满X元包邮:让你设置一个满多少元可以包邮,没达到这么多钱的话,固定运费就是多少钱。
{“threshold”: 100, “less_than_threshold_freight”: 10}
比如说,选择了自定义规则之后:就是下面会出来多个UI组件,你可以加多个规则,每个规则:加一个规则,选择发货到哪些哪些省份,多少重量以内是多少钱;每增加多少g,增加多少钱。
[
{
“provinces”: “山西,陕西,甘肃,辽宁,黑龙江,吉林”,
“threshold”: “100g”,
“threshold_freight”: 10,
“incr_step”: “2g”,
“incr_freight”: 2
},
{
“provinces”: “云南,广西,湖南,江西”,
“threshold”: “100g”,
“threshold_freight”: 5,
“incr_step”: “1g”,
“incr_freight”: 1
}
]
可以调整和修改运费模板的名称、类型、规则、备注,
准备提交订单的确认页面上,就会根据每个商品的运费模板,计算出来每个商品对应的一个运费,
订单中心会将订单的数据传送过来,然后这里会根据每个商品绑定的运费模板,计算出来每个商品对应的一个运费。包括一个订单的总运费。
看到这种场景,直接就上策略模式,如果你不用策略模式的话,可能代码会写成什么样子呢?
if (type == 1) {
// 200行代码
} else if(type == 2) {
// 300行代码
} else if(type == 3) {
// 1000行代码
}
策略模式实现
首先定义一个运费计算器的接口
输入运费模板FreightTemplateDTO和订单
返回运费数值。
/**
* 运费计算器接口
* @author
*
*/
public interface FreightCalculator {
/**
* 计算订单条目的运费
* @param freightTemplate 运费模板
* @param order 订单
* @param orderItem 订单条目
* @return 运费
* @throws Exception
*/
Double calculate(FreightTemplateDTO freightTemplate,
OrderInfoDTO order, OrderItemDTO orderItem) throws Exception;
}
四种策略对应四种实现:
FixedFreightCalculator- 固定运费计算器
ReachFreeFreightCalculator-满减策略
CustomRuleFreightCalculator-自定义规则计算器
DefaultFreightCalculator-默认运费计算器
/**
* 固定运费计算器
* @author
*
*/
@Component
public class FixedFreightCalculator implements FreightCalculator {
/**
* 计算订单条目的运费
* {“threshold”: 100, “less_than_threshold_freight”: 10}
* @param freightTemplate 运费模板
* @param order 订单
* @param orderItem 订单条目
* @return 运费
* @throws Exception
*/
public Double calculate(FreightTemplateDTO freightTemplate,
OrderInfoDTO order, OrderItemDTO orderItem) throws Exception {
JSONObject rule = JSONObject.parseObject(freightTemplate.getRule());
return rule.getDouble("fixed_freight");
}
}
/**
* 满X元包邮运费计算器
* @author
*
*/
@Component
public class ReachFreeFreightCalculator implements FreightCalculator {
/**
* 计算订单条目的运费
* {“threshold”: 100, “less_than_threshold_freight”: 10}
*
* @param freightTemplate 运费模板
* @param order 订单
* @param orderItem 订单条目
* @return 运费
* @throws Exception
*/
public Double calculate(FreightTemplateDTO freightTemplate,
OrderInfoDTO order, OrderItemDTO orderItem) throws Exception {
JSONObject rule = JSONObject.parseObject(freightTemplate.getRule());
Double threshold = rule.getDouble("threshold");
Double lessThanThresholdFreight = rule.getDouble("less_than_threshold_freight");
Double amount = orderItem.getPurchaseQuantity() * orderItem.getPurchasePrice();
if (amount >= threshold) {
return 0.0;
} else {
return lessThanThresholdFreight;
}
}
}
/**
* 自定义规则运费计算器
* @author
*
*/
@Component
public class CustomRuleFreightCalculator implements FreightCalculator {
/**
* 计算订单条目的运费
* [
* {
* “provinces”: “山西,陕西,甘肃,辽宁,黑龙江,吉林”,
* “threshold”: “100g”,
* “threshold_freight”: 10,
* “incr_step”: “2g”,
* “incr_freight”: 2
* },
* {
* “provinces”: “云南,广西,湖南,江西”,
* “threshold”: “100g”,
* “threshold_freight”: 5,
* “incr_step”: “1g”,
* “incr_freight”: 1
* }
* ]
*
* @param freightTemplate 运费模板
* @param order 订单
* @param orderItem 订单条目
* @return 运费
* @throws Exception
*/
public Double calculate(FreightTemplateDTO freightTemplate,
OrderInfoDTO order, OrderItemDTO orderItem) throws Exception {
String province = getProvinceFromAddress(order.getDeliveryAddress());
Double totalGrossWeight = orderItem.getGoodsGrossWeight() * orderItem.getPurchaseQuantity();
JSONArray rules = JSONArray.parseArray(freightTemplate.getRule());
for(int i = 0; i < rules.size(); i++) {
JSONObject rule = rules.getJSONObject(i);
String provinces = rule.getString("provinces");
if(!provinces.contains(province)) {
continue;
}
Double threshold = rule.getDouble("threshold");
Double thresholdFreight = rule.getDouble("threshold_freight");
Double incrStep = rule.getDouble("incr_step");
Double incrFreight = rule.getDouble("incr_freight");
if(totalGrossWeight <= threshold) {
return thresholdFreight;
} else {
return thresholdFreight + (totalGrossWeight - threshold) / incrStep * incrFreight;
}
}
return 0.0;
}
/**
* 从地址中提取省份
* @param address 地址
* @return 省份
*/
private String getProvinceFromAddress(String address) {
return address.substring(0, address.indexOf("省"));
}
}
将各种策略封装成工厂:
/**
* 运费计算器工厂
* @author
*
*/
@Component
public class FreightCalculatorFactory {
/**
* 固定运费计算器
*/
@Autowired
private FixedFreightCalculator fixedFreightCalculator;
/**
* 满X元包邮运费计算器
*/
@Autowired
private ReachFreeFreightCalculator reachFreeFreightCalculator;
/**
* 自定义规则运费计算器
*/
@Autowired
private CustomRuleFreightCalculator customRuleFreightCalculator;
/**
* 默认运费计算器
*/
@Autowired
private DefaultFreightCalculator defaultFreightCalculator;
/**
* 获取运费模板对应的运费计算器
* @param freightTemplate 运费模板
* @return 运费计算器
*/
public FreightCalculator get(FreightTemplateDTO freightTemplate) {
if(FreightTemplateType.FIXED.equals(freightTemplate.getType())) {
return fixedFreightCalculator;
} else if(FreightTemplateType.REACH_FREE.equals(freightTemplate.getType())) {
return reachFreeFreightCalculator;
} else if(FreightTemplateType.CUSTOM_RULE.equals(freightTemplate.getType())) {
return customRuleFreightCalculator;
}
return defaultFreightCalculator;
}
}
根据商品id,查询到对于的运费模板,然后获取运费计算器
/**
* 计算商品sku的运费
* @param goodsSkuDTO 商品sku DTO
* @return 商品sku的运费
*/
public Double calculateFreight(OrderInfoDTO order, OrderItemDTO orderItem) {
try {
// 获取商品对应的运费模板
Long goodsId = orderItem.getGoodsId();
GoodsDTO goods = commodityService.getGoodsById(goodsId);
FreightTemplateDTO freightTemplate = freightTemplateService.getById(
goods.getFreightTemplateId());
// 获取运费计算器
FreightCalculator freightCalculator = freightCalculatorFactory.get(freightTemplate);
Double freight = freightCalculator.calculate(freightTemplate, order, orderItem);
return freight;
} catch (Exception e) {
logger.error("error", e);
return 0.0;
}
}
- 本文链接: https://blog.zoozer.club/archives/-she-ji-mo-shi-gong-cheng-shi-jian--ce-lve-mo-shi---wan-cheng-ge-zhong-yun-fei-ji-suan-gui-ze
- 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!