设计模式-策略模式和工厂模式结合使用

  • 怎么把策略模式和工厂模式结合起来使用

如果大家对策略模式和工厂模式不是很了解的话可以先看前面文章
策略模式:https://www.jianshu.com/p/958281936901
工厂模式:https://www.jianshu.com/p/9078481e00c6

大家可能都用过微信支付,在使用微信支付付钱时候:

1、当我们的付款金额大于我们的余额时,会让我们使用银行卡支付,
2、余额充足的时候会让我们优先使用余额里面的钱
扣款策略一:
余额(blance) >= 付款金额(tradeAmout) 使用余额
扣款策略二:
余额(blance) < 付款金额(tradeAmout) 使用银行卡
很明显这是一个策略模式的实际应用,但是你还记得策略模式的缺陷吗?它的具体策略必须暴露出去,而且还要由上层模块初始化,这不适合,与迪米特法则不符( 迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。注:摘自百度百科,这个迪米特法则下次再细讲)冲突。高层模块对底层模块仅仅在接触层次上,而不应该是耦合关系。问题出了,我们应该想办法解决,正好工厂模式可以帮我们解决这个问题。但是引入工厂模式也有问题,工厂方法要指定一个类,它才能生产对象,我们用枚举来完成。
首先我们先建两个实体类WxBlance和WxTrade

import java.math.BigDecimal;

/**
 * @author shuliangzhao
 * @Title: WxBlance
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/28 23:50
 */
public class WxBlance {

    //余额
    private BigDecimal blance;

    public BigDecimal getBlance() {
        return blance;
    }

    public void setBlance(BigDecimal blance) {
        this.blance = blance;
    }
}

import java.math.BigDecimal;

/**
 * @author shuliangzhao
 * @Title: Trade
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/28 23:51
 */
public class WxTrade {
    private BigDecimal tradeAmout;

    private String tradeNo;

    private BigDecimal userAmout;

    public BigDecimal getUserAmout() {
        return userAmout;
    }

    public void setUserAmout(BigDecimal userAmout) {
        this.userAmout = userAmout;
    }

    public String getTradeNo() {
        return tradeNo;
    }

    public void setTradeNo(String tradeNo) {
        this.tradeNo = tradeNo;
    }

    public BigDecimal getTradeAmout() {
        return tradeAmout;
    }

    public void setTradeAmout(BigDecimal tradeAmout) {
        this.tradeAmout = tradeAmout;
    }
}

扣款策略接口

/**
 * @author shuliangzhao
 * @Title: Deduction
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/28 23:53
 */
public interface Deduction {

    public boolean exec(WxBlance wxBlance,WxTrade wxTrade);
}

扣款策略一

/**
 * @author shuliangzhao
 * @Title: BlanceDeduction
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/28 23:54
 */
public class BlanceDeduction implements Deduction {
    @Override
    public boolean exec(WxBlance wxBlance, WxTrade wxTrade) {
        if (wxBlance.getBlance().compareTo(wxTrade.getTradeAmout()) >= 0) {
            wxTrade.setUserAmout(wxBlance.getBlance());
        }
        return true;
    }
}

扣款策略二

/**
 * @author shuliangzhao
 * @Title: IdCardDeduction
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/28 23:54
 */
public class IdCardDeduction implements Deduction {
    @Override
    public boolean exec(WxBlance wxBlance, WxTrade wxTrade) {
        if (wxBlance.getBlance().compareTo(wxTrade.getTradeAmout()) < 0) {
            wxTrade.setUserAmout(wxTrade.getTradeAmout());
        }
        return true;
    }
}

扣款策略封装

/**
 * @author shuliangzhao
 * @Title: DedutionContext
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/28 23:58
 */
public class DedutionContext {

    private Deduction deduction;

    public DedutionContext(Deduction deduction) {
        this.deduction = deduction;
    }

    public boolean exec(WxBlance wxBlance,WxTrade wxTrade) {
        return deduction.exec(wxBlance,wxTrade);
    }
}

典型的策略上下文。策略模式的缺陷把所有策略类都暴露出去,怎么修改呢?使用工厂模式根据映射产生策略对象

策略枚举

/**
 * @author shuliangzhao
 * @Title: StrategyEnum
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/29 0:00
 */
public enum  StrategyEnum {

    BlanceDeduction("com.sl.factorystrategy.BlanceDeduction"),
    IdCardDeduction("com.sl.factorystrategy.IdCardDeduction");
    String value = "";
    private StrategyEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

策略工厂

/**
 * @author shuliangzhao
 * @Title: StrategyFactory
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/29 0:03
 */
public class StrategyFactory {

    public static Deduction getDeduction(StrategyEnum strategyEnum) {
        Deduction deduction = null;
        try {
            deduction = (Deduction)Class.forName(strategyEnum.getValue()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return deduction;
    }
}

扣款调用类

/**
 * @author shuliangzhao
 * @Title: DeductionFacade
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/29 0:06
 */
public class DeductionFacade {

    //扣款
    public static void deduct(WxBlance wxBlance,WxTrade wxTrade) {
        StrategyEnum strate = getStrate(wxBlance, wxTrade);
        Deduction deduction = StrategyFactory.getDeduction(strate);
        deduction.exec(wxBlance,wxTrade);
    }

    //获取扣款策略
    private static  StrategyEnum getStrate(WxBlance wxBlance,WxTrade wxTrade) {
        if (wxBlance.getBlance().compareTo(wxTrade.getTradeAmout()) < 0) {
            return StrategyEnum.IdCardDeduction;
        }else {
            return StrategyEnum.BlanceDeduction;
        }
    }
}

调用客户端client

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/29 0:10
 */
public class Client {

    public static void main(String[] args) {
        WxTrade wxTrade = new WxTrade();
        wxTrade.setTradeAmout(new BigDecimal("1000"));
        WxBlance wxBlance = new WxBlance();
        wxBlance.setBlance(new BigDecimal("999"));
        DeductionFacade.deduct(wxBlance,wxTrade);
        System.out.println(wxTrade.getUserAmout());
    }
}

执行结果

 

 

小结:
策略模式:负责对扣款封装,保证两个策略自由切换,以后增加策略也很容易

工厂模式:修正策略模式必须对外暴露问题,由工厂模式产生一个具体策略对象

posted @ 2019-06-01 10:47  爱在惜缘前  阅读(475)  评论(0编辑  收藏  举报