策略模式实战之优惠方式
策略模式的类图:
代码结构:
优惠方式父类:
/** * @author hejingyuan * */ public class AbstractIncentive implements Serializable { private static final long serialVersionUID = 1L; private long id; private int minAccount; private Integer feeFree; private String incentiveType; private long incentiveTypeId; //省略get set 方法 public PromotionResultDto calculate(Map<Integer, Integer> selectedGoods, Integer repeatTimes,PromotionActivity promotionActivity,int orderAmount,List<ProductDetail> list) { // TODO Auto-generated method stub return null; }
单品优惠子类:
/** * @author hejingyuan * */ public class IncentiveItemDiscount extends AbstractIncentive { private static final long serialVersionUID = 1L; public IncentiveItemDiscount(){ super.setId(0); this.itemCups = new Integer(0); this.itemDiscount = new Integer(0); } private Integer itemCups; private Integer itemDiscount; //省略get set 方法 @Override public PromotionResultDto calculate(Map<Integer, Integer> selectedGoods, Integer repeatTimes,PromotionActivity promotionActivity,int orderAmount,List<ProductDetail> list) { // 单品折扣 PromotionResultDto promotionResultDto=new PromotionResultDto(); promotionResultDto.setId(promotionActivity.getId()); promotionResultDto.setName(promotionActivity.getName()); IncentiveItemDiscount incentiveItemDiscount=(IncentiveItemDiscount)promotionActivity.getPromotionTemplate().getIncentive(); // 商品或商品类别的限制 String promotionRule=promotionActivity.getPromotionTemplate().getLimitedProduct(); int cups=0; //订单包括商品为不限时,选择价格最廉价的优惠 if(promotionActivity.getPromotionTemplate().getTypes().equals(0)||promotionRule.equals("")||promotionRule==null){ for (Map.Entry<Integer, Integer> entry : selectedGoods.entrySet()) { cups += entry.getValue();//订单中包括的总杯数 } //倍数 if(promotionActivity.getPromotionTemplate().getMinCups()!=0){ cups=cups/promotionActivity.getPromotionTemplate().getMinCups(); } //repeatTimes=0 不限制反复次数 if(repeatTimes<cups && repeatTimes!=0){ int promotionProductPrice=getPromotionProductPrice(incentiveItemDiscount,list,repeatTimes);//优惠商品数的总价格 promotionResultDto.setAmount(incentiveItemDiscount.getItemDiscount()*promotionProductPrice/100); promotionResultDto.setTimes(repeatTimes); }else{ int promotionProductPrice=getPromotionProductPrice(incentiveItemDiscount,list,cups);//优惠商品数的总价格 promotionResultDto.setAmount(incentiveItemDiscount.getItemDiscount()*promotionProductPrice/100); promotionResultDto.setTimes(cups); } return promotionResultDto; } Integer relation=promotionActivity.getPromotionTemplate().getRelation(); String[] rules = StringUtils.split(promotionRule, ","); //and if(relation.equals(1)){ //整除(订单中某商品的杯数/活动中此商品的最小杯数) if(promotionActivity.getPromotionTemplate().getCups()!=0){ cups=selectedGoods.get(Integer.parseInt(rules[0]))/promotionActivity.getPromotionTemplate().getCups(); for(int i=0;i<rules.length;i++){ //取最小值 if((selectedGoods.get(Integer.parseInt(rules[i]))/promotionActivity.getPromotionTemplate().getCups())<cups){ cups=selectedGoods.get(Integer.parseInt(rules[i]))/promotionActivity.getPromotionTemplate().getCups(); } } } }else{ //or 或者 无关系时。即仅仅选择了一种类型或者一种商品的情况 cups=0; for(int i=0;i<rules.length;i++){ //累加全部商品杯数 if(null!=selectedGoods.get(Integer.parseInt(rules[i]))&&selectedGoods.get(Integer.parseInt(rules[i]))>=promotionActivity.getPromotionTemplate().getCups()){ cups+=selectedGoods.get(Integer.parseInt(rules[i])); } } if(promotionActivity.getPromotionTemplate().getCups()!=0){ cups=cups/promotionActivity.getPromotionTemplate().getCups(); } } //repeatTimes=0 不限制反复次数 if(repeatTimes<cups && repeatTimes!=0){ int promotionProductPrice=getPromotionProductPrice(incentiveItemDiscount,list,repeatTimes);//优惠商品数的总价格 promotionResultDto.setAmount(incentiveItemDiscount.getItemDiscount()*promotionProductPrice/100); promotionResultDto.setTimes(repeatTimes); }else{ int promotionProductPrice=getPromotionProductPrice(incentiveItemDiscount,list,cups);//优惠商品数的总价格 promotionResultDto.setAmount(incentiveItemDiscount.getItemDiscount()*promotionProductPrice/100); promotionResultDto.setTimes(cups); } return promotionResultDto; } private int getPromotionProductPrice(IncentiveItemDiscount incentiveItemDiscount, List<ProductDetail> list,int cups) { //从list中找出优惠商品。进行优惠金额计算 int promotionProductPrice=0; for(int i=0;i<cups*incentiveItemDiscount.getItemCups();i++){ promotionProductPrice+=list.get(i).getPrice(); } return promotionProductPrice; } }
直减,整单折扣 省略...
优惠模板:
/** * @author hejingyuan * */ public class PromotionTemplate implements Serializable{ private static final long serialVersionUID = 1L; private long id; private String name; private Integer minCups; private String limitedProduct; private AbstractIncentive incentive; //去掉部分属性及get set方法 }
策略模式应用:
优惠计算及结构:
部分代码:
public TotalPromotionResultDto calcPromotion(long providerId, long cityId, long zoneId, int customerId, Map<Integer, Integer> selectedGoods, PurchaseFunction functionEntry, long platformId) { //依据開始时间从小到大排序 List<PromotionActivity> activityList = selectPromotionActivities(providerId, cityId, zoneId,customerId,selectedGoods, functionEntry, platformId); logger.debug("acquire promotion activity. list.size:{}", activityList.size()); if(activityList.size()==0||null==activityList){ return null; } List<PromotionResultDto> results = new ArrayList<PromotionResultDto>(); List<PromotionResultDto> result = new ArrayList<PromotionResultDto>(); TotalPromotionResultDto totalPromotionResultDto=new TotalPromotionResultDto(); int amount=0; for (PromotionActivity item : activityList) { PromotionActivity pa=promotionActivitySbo.loadPromotionActivityById(item.getId()); // 商品id和相应杯数 或者 类别id和相应杯数 Map<Integer, Integer> goods=ProductType(selectedGoods,item); //订单总金额(分) int orderAmount=getTotalAmount(selectedGoods); List<ProductDetail> list=mapToList(selectedGoods); PromotionResultDto pr = pa.calculatePromotionResult(goods,item.getRepeatTimes(),pa,orderAmount,list); logger.debug("calculate promotion activity. activityId:{}, amount:{}", pr.getId(), pr.getAmount()); //假设优惠金额同样,再找開始时间近期的。终于选中一个优惠金额最大的(分) if(pr.getAmount()>amount){ amount=pr.getAmount(); results.add(0,pr); } //处理优惠金额大于订单总金额问题 if(amount>orderAmount){ amount=orderAmount; } } PromotionActivity promotionActivity=promotionActivityDaoProxy.get(results.get(0).getId()); PromotionTemplate pt=promotionTemplateDaoProxy.get(promotionActivity.getPromotionTemplate().getId()); Integer isFeeFree=pt.getIncentive().getFeeFree(); if(isFeeFree.equals(0)){ totalPromotionResultDto.setFeeFree(false); }else{ totalPromotionResultDto.setFeeFree(true); } result.add(0, results.get(0)); totalPromotionResultDto.setTotalFreeAmount(amount); totalPromotionResultDto.setPromotionList(result); return totalPromotionResultDto; }
public PromotionActivity loadPromotionActivityById(long promotionActivityId) { PromotionActivity promotionActivity=promotionActivityDaoProxy.get(promotionActivityId); PromotionTemplate pt=promotionTemplateDaoProxy.get(promotionActivity.getPromotionTemplate().getId()); String incentiveType=pt.getIncentive().getIncentiveType(); long id=pt.getIncentive().getIncentiveTypeId(); switch(incentiveType){ case "p"://直减 promotionActivity.setRebatesEngine(orderPricecutDaoProxy.get(id)); break; case "o"://整单折扣 promotionActivity.setRebatesEngine(orderDiscountDaoProxy.get(id)); break; case "i"://单品优惠 promotionActivity.setRebatesEngine(itemDiscountDaoProxy.get(id)); break; } return promotionActivity; } public void setRebatesEngine(AbstractIncentive incentive){ this.getPromotionTemplate().setIncentive(incentive); }
public PromotionResultDto calculatePromotionResult(Map<Integer, Integer> selectedGoods,Integer repeatTimes,PromotionActivity promotionActivity,int orderAmount,List<ProductDetail> list) { PromotionResultDto promotionResultDto; promotionResultDto = this.getRebatesEngine().calculate(selectedGoods, repeatTimes,promotionActivity,orderAmount,list); return promotionResultDto; } public AbstractIncentive getRebatesEngine(){ return this.getPromotionTemplate().getIncentive(); }
通过这个calculate方法,会调用各自的子类的实现即直减,整单折扣或者是单品折扣。假设不理解这句话,那么接着往下看...
多态:
多态,是面向对象的程序设计语言最核心的特征。多态,意味着一个对象有着多重特征,能够在特定的情况下。表现不同的状态,从而相应着不同的属性和方法。通俗的说,同一操作作用于不同的对象,能够有不同的解释,产生不同的执行结果。在执行时,能够通过指向基类的指针,来调用实现派生类中的方法。
从程序设计的角度而言,多态能够这样来实现
public interface Parent//父类接口 { public void simpleCall(); } public class Child_A implements Parent { public void simpleCall(); { //详细的实现细节。 } } public class Child_B implements Parent { public void simpleCall(); { //详细的实现细节; } }
所以。我们对于抽象的父类或者接口给出了我们的详细实现后。pa 能够全然不用管实现的细节。仅仅訪问我们定义的方法,就能够了。其实。这就是多态所起的作用,能够实现控制反转这在大量的J2EE轻量级框架中被用到。比方Spring的依赖注入机制。
多态原理:当方法被调用时,不管对象是否被转换为其父类,都仅仅有位于对象继承最末端的方法实现会被调用。也就是说它是依照其执行时类型而非编译时类型进行动态绑定调用的。
附
/** * */ package com.lyancafe.csr.model; import java.io.Serializable; import java.util.Date; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import com.lyancafe.promotion.sbo.PromotionActivitySbo; import com.lyancafe.promotion.sbo.PromotionResultDto; import com.lyancafe.util.DateTimeUtil; /** * @author hejingyuan * */ public class PromotionActivity implements Serializable{ public PromotionActivity() { super(); this.totalTimes = new Integer(0); this.dayTotalTimes = new Integer(0); this.customerTotalTimes = new Integer(0); this.customerDayTotalTimes = new Integer(0); this.repeatTimes = new Integer(0); } @Autowired private PromotionActivitySbo promotionActivitySbo; private static final long serialVersionUID = 1L; private long id; private String name; private String balanceName; private String comments; private PromotionTemplate promotionTemplate; private OrderPlatform orderPlatform; public OrderPlatform getOrderPlatform() { return orderPlatform; } public void setOrderPlatform(OrderPlatform orderPlatform) { this.orderPlatform = orderPlatform; } private Date startTime; private Date endTime; private String startTimeStr; private String endTimeStr; private Integer uniqueness; private Integer totalTimes; private Integer dayTotalTimes; private Integer customerTotalTimes; private Integer customerDayTotalTimes; private Integer repeatTimes; private String regionLimitType; private String regionLimit; private Integer newCustomer; private String active = "Y"; private Integer createBy = new Integer(0); private Integer updateBy = new Integer(0); //created private Date created = new Date(); //update time default it's equal created private Date updated = new Date(); public String getStartTimeStr() { return null == startTimeStr ?DateTimeUtil.formatDateTime(startTime) : startTimeStr; } public void setStartTimeStr(String startTimeStr) { this.startTimeStr = startTimeStr; } public String getEndTimeStr() { return null == endTimeStr ?
DateTimeUtil.formatDateTime(endTime) : endTimeStr; } public void setEndTimeStr(String endTimeStr) { this.endTimeStr = endTimeStr; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getBalanceName() { return balanceName; } public void setBalanceName(String balanceName) { this.balanceName = balanceName; } public String getComments() { return comments; } public void setComments(String comments) { this.comments = comments; } public PromotionTemplate getPromotionTemplate() { return promotionTemplate; } public void setPromotionTemplate(PromotionTemplate promotionTemplate) { this.promotionTemplate = promotionTemplate; } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public Integer getUniqueness() { return uniqueness; } public void setUniqueness(Integer uniqueness) { this.uniqueness = uniqueness; } public Integer getTotalTimes() { return totalTimes; } public void setTotalTimes(Integer totalTimes) { this.totalTimes = totalTimes; } public Integer getDayTotalTimes() { return dayTotalTimes; } public void setDayTotalTimes(Integer dayTotalTimes) { this.dayTotalTimes = dayTotalTimes; } public Integer getCustomerTotalTimes() { return customerTotalTimes; } public void setCustomerTotalTimes(Integer customerTotalTimes) { this.customerTotalTimes = customerTotalTimes; } public Integer getCustomerDayTotalTimes() { return customerDayTotalTimes; } public void setCustomerDayTotalTimes(Integer customerDayTotalTimes) { this.customerDayTotalTimes = customerDayTotalTimes; } public Integer getRepeatTimes() { return repeatTimes; } public void setRepeatTimes(Integer repeatTimes) { this.repeatTimes = repeatTimes; } public String getRegionLimitType() { return regionLimitType; } public void setRegionLimitType(String regionLimitType) { this.regionLimitType = regionLimitType; } public String getRegionLimit() { return regionLimit; } public void setRegionLimit(String regionLimit) { this.regionLimit = regionLimit; } public Integer getNewCustomer() { return newCustomer; } public void setNewCustomer(Integer newCustomer) { this.newCustomer = newCustomer; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getActive() { return active; } public void setActive(String active) { this.active = active; } public Integer getCreateBy() { return createBy; } public void setCreateBy(Integer createBy) { this.createBy = createBy; } public Integer getUpdateBy() { return updateBy; } public void setUpdateBy(Integer updateBy) { this.updateBy = updateBy; } public Date getCreated() { return created; } public void setCreated(Date created) { this.created = created; } public Date getUpdated() { return updated; } public void setUpdated(Date updated) { this.updated = updated; } public long getIncentiveTypeId(){ return this.promotionTemplate.getIncentive().getIncentiveTypeId(); } public String getIncentiveType(){ return this.promotionTemplate.getIncentive().getIncentiveType(); } public void setRebatesEngine(AbstractIncentive incentive){ this.getPromotionTemplate().setIncentive(incentive); } public AbstractIncentive getRebatesEngine(){ return this.getPromotionTemplate().getIncentive(); } PromotionResultDto calculatePromotionResult(Map<Integer, Integer> selectedGoods,Integer repeatTimes) { PromotionResultDto promotionResultDto; promotionResultDto = this.getRebatesEngine().calculate(selectedGoods, repeatTimes); return promotionResultDto; } }