策略模式的类图:
代码结构:
优惠方式父类:
/**
* @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();
{
//具体的实现细节;
}
}
//当然还可以有其他的实现
然后,我们就可以看到多态所展示的特性了:
Parent pa = new Child_A();
pa.simpleCall()则显然是调用Child_A的方法;
Parent pa = new Child_B();
pa.simpleCall()则是在调用Child_B的方法。
所以,我们对于抽象的父类或者接口给出了我们的具体实现后,pa 可以完全不用管实现的细节,只访问我们定义的方法,就可以了。事实上,这就是多态所起的作用,可以实现 控制反转这在大量的J2EE 轻量级框架中被用到,比如Spring的依赖注入机制。
所以,我们对于抽象的父类或者接口给出了我们的具体实现后,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;
}
}